我已经连续几天跟踪这个问题,所以我想我会在这里发布它以帮助其他人解决同样的问题,并了解更多有关原因的信息。我在本文末尾将问题代码简化为两个类模块。
基本上,简化的场景是这样的:两个类模块,Parent和Child,其中Child实现Parent。 Parent中的某个位置是行TypeOf Me Is Child
,其中Me
可以是任何对象。
根据我的理解,当TypeOf...Is
行编译为P代码(Debug>编译或调用方法)并保存到文件(.xlsm或.xlsb)时,它会导致文件不正常打开。代码运行正常,但是当文件被保存,关闭和重新打开时,它会在打开(或打开VBE)时发出错误,指出Invalid data format
或Error accessing file. Network connection may have been lost
,并且父模块不能更长时间打开,也不能运行任何VBA(在立即窗口中尝试?1=1
并且它会给出相同的错误。)
如果使用TypeName()
而非TypeOf...Is
检查类型,则不会出现此问题(这是我在项目中使用的解决方案)。
任何人都可以更清楚地知道这里到底出了什么问题,或者至少确认我在导致问题的原因(P代码)方面走在正确的轨道上?
PS是的,我知道父母知道这个孩子的设计很差,但我接近一次性项目的结束,不值得花时间重新设计。有用的链接:
课程模块:
父:
Option Explicit
' Class: Parent
' The problem (so far as I can tell):
' When the compiled version of the method below is saved to the file, the file
' will no longer load properly. Upon saving and reopening the file, I get a
' "Invalid data format" error, and the code for this class module can no longer be
' accessed. Furthermore, no VBA code will run after this happens. Try typing "?1=1"
' into the Immediate Window - you'll get another "Invalid data format" window.
' Alternatively, the error will be "Error accessing file. Network connection may
' have been lost." if the code is changed from using "Me" to "tmp" as noted in the
' comments in DoSomething().
' Steps to replicate:
' 1. Debug > Compile VBAProject.
' 2. Save file.
' 3. Close Excel.
' 4. Reopen file (and may need to open VBE).
Public Sub DoSomething()
' The TypeOf...Is statement seems to be what causes the problem.
' Note that checking "Me" isn't the cause of the problem (merely makes
' for shorter demo code); making a "Dim tmp as Object; set tmp = new Collection"
' and checking "TypeOf tmp Is Child" will cause the same problem.
' Also note, changing this to use TypeName() resolves the issue.
' Another note, moving the TypeOf...Is to a "Private Sub DoSomethingElse()" has
' no effect on the issue. Moving it to a new, unrelated class, however, does
' not cause the issue to occur.
If TypeOf Me Is Child Then
Debug.Print "Parent"
End If
End Sub
儿童:
Option Explicit
' Class: Child
Implements Parent
Private Sub Parent_DoSomething()
Debug.Print "Child"
End Sub
答案 0 :(得分:2)
问题本身不是TypeOf
语句。问题是您设置了VBA无法解决的循环依赖关系。正如user2140173所述,VBA并未真正实现多态。
您创建的循环引用是,接口"Parent"
的定义包括(需要存在)对象"Child"
,类"Child"
的定义实现了(需要存在){{ 1}}。因此,VBA无法在编译时正确创建接口,并且下次保存,关闭并重新打开工作簿和VB编辑器时,接口类将损坏且无法访问。
OP可能被误解为暗示"Parent"
归咎于某种原因。但是,TypeOf语句并不特殊。 interface 类中所有引用本身是TypeOf .. Is
interface 类的类的语句都将设置循环依赖问题。
例如:
Person.cs
IMPLEMENTS
Boy.cs
'Class Person
Option explicit
Public Sub SaySomething()
Dim B as Boy '<--- here we cause the problem!
End sub
所以我希望您能看到Boy.cs实现了包含Boy.cs的Person.cs,而Boy.cs实现了包含Boy.cs的Person.cs .... VBA在这一点上很疯狂:)
不幸的是,VB编辑器没有提供比“无效数据格式”错误或“访问文件错误。网络连接可能已丢失”更有用的错误消息。这让用户感到困惑!
解决方案是从接口类的源代码中删除这些语句。如果由于在接口类中实际编写了许多业务逻辑而被证明很难做到,那么一种有用的方法是将业务逻辑移到一个单独的类中。只需单独执行此操作即可解决Interface的编译问题,并使您的代码再次运行。 以我自己的经验,出于这个原因,我特意尝试从接口类中删除任何业务逻辑,以确保不会发生此类错误,并且接口类变得非常简单-仅列出方法签名。如果我不想在将实现接口的每个类中重复通用的业务逻辑,那么我将创建一个附加类来保存此通用业务逻辑,并确保接口要求该类存在。 例如:
iMusicalInstrument.cs
'Class Boy
Option explicit
Implements Person
Private Sub Person_SaySomething()
Debug.Print "Hello"
End sub
csMusicalInstrumentCommon.cs
'iMusicalInstrument interface
Option Explicit
Property Get Common() as csMusicalInstrumentCommon
End Property
csTrumpet.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 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
:)
答案 1 :(得分:1)
VBA不支持类多态。
我认为你误解了关键字Implements
的目的。
当你想要一个类来实现接口时使用它 - 而不是另一个类(好吧,至少不是字面意思,因为VBA中的接口是另一个类模块对象)
请参阅this answer for better understanding of the Implements
keyword in VBA
有关VBA多态性的信息,请参阅this