当这两个子程序在类内时,它们执行相同的操作。
Sub DemoMe( )
Me.AboutMe ' Calls AboutMe procedure.
End Sub
Sub DemoMe( )
AboutMe ' Does the same thing.
End Sub
这有什么意义呢?Me 关键字有什么作用吗?一个对象访问自己的成员的首选方式是什么?
来自VBA语言规范(5.3.1.5):
每个作为方法的过程都有一个名为"当前对象"的隐式ByVal参数,该参数对应于调用该方法的目标对象。当前对象充当具有过程范围的匿名本地变量,其声明类型是包含方法声明的类模块的类名。在方法激活期间,当前对象变量的数据值是创建该激活的过程调用的目标对象。当前对象可以使用Me关键字在方法的<procedure-body>中访问,但不能被赋值或以其他方式修改。
就是这样,只是一个"免费"的本地变量,用于引用调用该方法的特定实例。在它们调用期间,这也恰好是过程的默认上下文,因此如果代码旨在操作当前实例,则可以省略它。尽管如同@HansPassant在上面的评论中指出的那样,它还允许编辑器绑定到接口并提供智能感知。
虽然如此,但有几种情况下您需要使用它(这绝不是穷尽性列表):
命名冲突:
如果您的类具有隐藏内置VBA函数的成员,则可以使用它来使范围明确:
Public Property Get Left() As Long
'...
End Property
Public Property Get Right() As Long
'...
End Property
Public Property Get Width() As Long
Width = Me.Right - Me.Left
End Property
权益检查:
Public Function Equals(other As Object) As Boolean
If other Is Me Then
Equals = True
Exit Function
End If
'...
End Function
流畅的函数:
这是一个有用的对象组合模式 - 您执行操作,然后返回类的实例,以便它们可以“链接”。在许多情况下,Excel的Range
接口使用此模式:
Public Function Add(Value As Long) As Class1
'Do whatever.
Set Add = Me
End Function
Public Sub Foo()
Dim bar As New Class1
bar.Add(1).Add(1).Add 1
End Sub
this
一样,使用Me
也没有特别的原因:它是一个保留标识符,表示类的当前实例 - 如何使用这个实例取决于你的想象力。Me
关键字来访问其公共接口。与其他语言中的this
一样,我甚至会称其为多余。然而,有时候明确地限定成员调用使用Me
可以是一个好主意,特别是当类具有VB_PredeclaredId
属性(例如任何):在代码中引用UserForm1,在UserForm1中代码后台将产生对该类的默认实例的引用,而使用Me
限定成员调用将产生对该类的当前实例的引用。UserForm1
的代码后台中时,UserForm
的成员以及当您在Sheet1
的代码后台中时,Worksheet
的成员并不容易找到。但由于继承的成员出现在智能感知/自动完成中,您可以输入Me.
并浏览从基类继承的成员列表,否则您需要知道这些成员才能调用它们。With
块内引用对象实例成为可能,内部是工厂方法 - 就像这个GridCoord类。Public Function Create(ByVal xPosition As Long, ByVal yPosition As Long) As IGridCoord
With New GridCoord
.X = xPosition
.Y = yPosition
Set Create = .Self
End With
End Function
Public Property Get Self() As IGridCoord
Set Self = Me
End Property
GridCoord
类公开了X
和Y
属性的getter和setter,但IGridCoord
接口只公开了getter。因此,针对IGridCoord
接口编写的代码实际上正在使用只读属性。TypeName(Me)
作为错误的Source
。
Builder Pattern
以返回Me
而著称,这使得可以通过链接成员调用逐步构建复杂对象的“流畅API”设计成为可能,其中每个成员都返回Me
(除了最后的Build
调用,它返回正在构建的类的类型)。Dim thing As Something
Set builder = New ThingBuilder
Set thing = builder _
.WithFoo(42) _
.WithBar("test") _
.WithSomething _
.WithSomethingElse
.Build
@PBeezy: 除了我的评论:
Me指的是它来自的对象,因此AboutMe驻留在类中。如果您有另一个实例,比如说这是Class1,您需要dim c as Class1,一旦您在Class1中创建了一个实例,您需要告诉编译器您正在使用哪个类,即持有类或在哪里创建的实例,在这种情况下,me.class1.aboutme在逻辑上是有效的。您还可以为工作簿中的每个单元格创建一个类,然后可以从B1的类引用A1的类。此外,如果有一个名为AboutMe的公共函数/子程序,这也很有帮助。
类(clsPerson)
Public c1 As clsPerson
Public strPersonName As String
Public Function NAME_THIS_PERSON(strName As String)
strPersonName = strName
End Function
Public Function ADD_NEW_CHILD(strChildName As String)
Set c1 = New clsPerson
c1.strPersonName = strChildName
End Function
普通模块
Sub test()
Dim c As New clsPerson
c.NAME_THIS_PERSON "Mother"
c.ADD_NEW_CHILD "Nathan"
Debug.Print c.strPersonName
Debug.Print c.c1.strPersonName
End Sub
Mother
Nathan
AboutMe
位于类中。如果您有另一个实例,比如说这是Class1
,您需要声明dim c as Class1
,一旦您在Class1
中创建了一个实例,您需要告诉编译器您正在使用哪个类,即持有类或创建的实例,在那里,me.class1.aboutme
在逻辑上是有效的。您还可以为工作簿中的每个单元格创建一个类,然后您可以从B1
的类引用A1
的类。此外,如果有一个名为 AboutMe 的公共函数/子程序,这也会有所帮助。 :o) - Nathan_SavClass1.Copy As Class1
。 - Comintern