“TypeOf…Is Child” from Parent causes broken Excel file

前端 未结 2 851
再見小時候
再見小時候 2021-01-19 02:47

I\'ve been tracking down this issue for several days, so I thought I\'d post it here to help others with the same problem, as well as learn more about the cause. I\'ve simpl

相关标签:
2条回答
  • 2021-01-19 03:25

    VBA does not support class polymorphism.

    I think you are misunderstanding the purpose of the keyword Implements.

    It's used when you want a class to implement an Interface - not another class ( well, at least not literally because an Interface in VBA is another class module object )

    See this answer for better understanding of the Implements keyword in VBA

    Also refer to this for info about VBA polymorphism

    0 讨论(0)
  • 2021-01-19 03:29

    IMPLEMENTS statement causes circular dependency

    The issue is not the TypeOf statement per se. The issue is that you have set up a circular dependency that VBA cannot resolve. As user2140173 mentioned VBA does not truly implement polymorphism. The circular reference you have created is that the definition of your interface "Parent" includes (requires existence of) your object "Child" and the definition of your class "Child" implements (requires existence of) "Parent". Therefore VBA cannot properly create the interface at compile time and the interface class becomes corrupted and inaccessible next time you have saved, closed and re-opened the workbook and VB Editor.

    The OP could be misinterpreted as implicating the statement TypeOf .. Is as being somehow to blame. However, the TypeOf statement is not special. Any statement at all in the interface class that references a class that itself IMPLEMENTS the interface class will set up the circular dependency problem. For example:

    Person.cs

    'Class Person
    Option explicit
    
    Public Sub SaySomething()
       Dim B as Boy            '<--- here we cause the problem!
    End sub 
    

    Boy.cs

    'Class Boy
    Option explicit
    
    Implements Person
    
    Private Sub Person_SaySomething()
       Debug.Print "Hello"
    End sub
    

    So i hope you can see that Boy.cs Implements Person.cs which contains a Boy.cs which Implements a Person.cs which contains a Boy.cs .... VBA goes crazy at this point :)

    It's a little unfortunate that the VB Editor doesn't give a more helpful error message than the "Invalid data format" error or the "Error accessing file. Network connection may have been lost." which leaves the User baffled!

    The solution is to remove these statement(s) from the source code of the interface class. If this proves difficult to do because you have a lot of business logic actually written in the interface class then a useful approach is to move the business logic out to a separate class. Simply doing this on its own can resolve the compile problem with the Interface and get your code running again. In my own experience, for this very reason I deliberately try to remove any business logic from the interface class to ensure this kind of error cannot occur, and the interface classes become extremely simple - just a list of method signatures. If there is common business logic that I don't want to have to duplicate in each of the classes that will IMPLEMENT my interface then I create an additional class to hold this common business logic and ensure that the interface requires this class to exist. For example:

    iMusicalInstrument.cs

    'iMusicalInstrument interface
    Option Explicit
    Property Get Common() as csMusicalInstrumentCommon
    End Property
    

    csMusicalInstrumentCommon.cs

    'MusicalInstrumentCommon class
    Option Explicit
    ' add any methods you want to be available to all implementers of the interface.
    Property Get GUID() as string        '<-- just an example, could be any method
         GUID = 'function to create a GUID
    End Property
    

    csTrumpet.cs

    ' csTrumpet class
    Option Explicit
    Implements iMusicalInstrument
    Private mCommon As csMusicalInstrumentCommon
    Private Sub Class_Initialize()
        Set mCommon = New csMusicalInstrumentCommon
    End Sub
    Private Sub Class_Terminate()
        Set mCommon = Nothing
    End Sub
    Private Property Get iMusicalInstrument_Common() As csMusicalInstrumentCommon
        Set iMusicalInstrument_Common = mCommon
    End Property
    

    Usage

    Public Sub Test()
        Dim Trumpet As New csTrumpet
        Dim iTrumpet As iMusicalInstrument
        Set iTrumpet = Trumpet
        Debug.Print iTrumpet.Common.GUID
    End Sub
    

    :)

    0 讨论(0)
提交回复
热议问题