VBA是否破坏了范围界定?

VBA是否破坏了范围界定?,vba,com,scoping,Vba,Com,Scoping,假设您在名为Module1的模块中有此代码: Option Explicit Private Type TSomething Foo As Integer Bar As Integer End Type Public Something As TSomething 在等效C代码中,如果将Something字段public,代码将不再编译,因为不一致的可访问性-字段的类型比字段本身的可访问性差。这是有道理的 但是,在VBA中,您可以在模块2中包含此代码: Sub DoSome

假设您在名为
Module1
的模块中有此代码:

Option Explicit

Private Type TSomething
    Foo As Integer
    Bar As Integer
End Type

Public Something As TSomething
在等效C代码中,如果将
Something
字段
public
,代码将不再编译,因为不一致的可访问性-字段的类型比字段本身的可访问性差。这是有道理的

但是,在VBA中,您可以在模块2中包含此代码:

Sub DoSomething()
    Module1.Something.Bar = 42
    Debug.Print Module1.Something.Bar
End Sub
当你输入它时,你会得到IntelliSense,它会编译,它会运行,它会输出
42


为什么??从COM的角度来看,它是如何工作的?它是语言规范的一部分吗?

根据我的评论,VBA公开私有类型,就像它公开私有枚举一样

VBA假定您可以在消费上下文中使用TypeInfo,但它不允许您声明或创建这些类型或枚举的实例

这是部分信息:

访问控制应用于名称

名称的访问说明符与其类型无关

但将标准模块中的私有类型看作类似于“PublicNotCreatable”类的东西可能是有用的。如果提供公共包装,则可以在主机模块外部访问该类型

但是当类型在公共类模块中时,VBA处理事情的方式不同

以下是扩展的
模块1

Option Explicit

Private Type TSomething
    Foo As Integer
    Bar As Integer
End Type

Public Type TOtherThing
    Foo As Integer
    Bar As Integer
End Type

Public Type TWrapperThing
  Something As TSomething
End Type

Public Something As TSomething
Public Otherthing As TOtherThing
Public Wrapperthing As TWrapperThing

Public Function GetSomething() As TSomething
  GetSomething.Foo = 1
End Function

Public Function GetOtherthing() As TOtherThing
  GetOtherthing.Foo = 1
End Function
Option Explicit

Sub DoThings()

'Compile Error: User-defined type not defined
  'Dim oSomething As TSomething
  Dim vSomething As Variant
  
  Dim oOtherthing As Module1.TOtherThing
  Dim vOtherthing As Variant
  Dim oWrapperthing As Module1.TWrapperThing
  
  Module1.Something.Foo = 42
  Module1.Otherthing.Foo = 42
  Module1.Wrapperthing.Something.Foo = 42

  'Compile Error: Only user-defined types defined in public object modules can be coerced to or from a variant or passed to late-bound functions
  'vSomething = Module1.Something
  'vOtherthing = Module1.Otherthing
  
  oOtherthing = Module1.Otherthing
  oOtherthing.Foo = 43
  
  'Is 43 > 42?
  Debug.Assert oOtherthing.Foo > Module1.Otherthing.Foo
  
'Compile Errors: "GetSomething" User-defined type not defined
  'Module1.GetSomething.Foo = 42
  'Module1.GetSomething().Foo = 42
  
  Module1.GetOtherthing.Foo = 42
  Module1.GetOtherthing().Foo = 42

End Sub
模块2
展开:

Option Explicit

Private Type TSomething
    Foo As Integer
    Bar As Integer
End Type

Public Type TOtherThing
    Foo As Integer
    Bar As Integer
End Type

Public Type TWrapperThing
  Something As TSomething
End Type

Public Something As TSomething
Public Otherthing As TOtherThing
Public Wrapperthing As TWrapperThing

Public Function GetSomething() As TSomething
  GetSomething.Foo = 1
End Function

Public Function GetOtherthing() As TOtherThing
  GetOtherthing.Foo = 1
End Function
Option Explicit

Sub DoThings()

'Compile Error: User-defined type not defined
  'Dim oSomething As TSomething
  Dim vSomething As Variant
  
  Dim oOtherthing As Module1.TOtherThing
  Dim vOtherthing As Variant
  Dim oWrapperthing As Module1.TWrapperThing
  
  Module1.Something.Foo = 42
  Module1.Otherthing.Foo = 42
  Module1.Wrapperthing.Something.Foo = 42

  'Compile Error: Only user-defined types defined in public object modules can be coerced to or from a variant or passed to late-bound functions
  'vSomething = Module1.Something
  'vOtherthing = Module1.Otherthing
  
  oOtherthing = Module1.Otherthing
  oOtherthing.Foo = 43
  
  'Is 43 > 42?
  Debug.Assert oOtherthing.Foo > Module1.Otherthing.Foo
  
'Compile Errors: "GetSomething" User-defined type not defined
  'Module1.GetSomething.Foo = 42
  'Module1.GetSomething().Foo = 42
  
  Module1.GetOtherthing.Foo = 42
  Module1.GetOtherthing().Foo = 42

End Sub

这听起来很清楚Java是如何工作的,不是因为这个问题是关于Java的,而是无论如何。这对我来说是有道理的,但话说回来。。。我是Java-guy.VBA公开私有类型,就像它公开私有枚举一样。它假设您可以在使用上下文中使用TypeInfo,但它不允许您声明这些类型或枚举的实例。为什么不呢?后期绑定是VB的一项功能,所以客户端代码不会无法访问成员。这在C#中也没有什么不同,你可以使用反射来访问私有成员。虽然我不能权威地发言,但我怀疑这与VBA和COM广泛使用
IDispatch
IUnknown
有关。编译器似乎正在访问
模块1.Something
,方法是将其视为对象而不是名称空间,然后查询接口以查看它是否可以成功调用
Something.Bar
<代码>某些内容通过成为
Public
而公开,因此它不需要访问该类型-它查询其接口以查看是否支持属性
。请注意,如果不这样做(有点像duck类型),后期绑定会困难得多。Add
Debug.Print TypeName(Module1.Something)
提供了一个额外的线索,说明COM正在检查接口——它产生的错误是(我的重点)“只有在公共对象模块中定义的用户定义类型才能强制转换为变量或从变量转换为变量,或传递给后期绑定的函数。”
Debug.Print TypeName(Module1.Something.Bar)
愉快地吐出“Integer”。