为什么VBA中的Me关键字无法访问其自身模块中的私有过程?

17

我刚刚发现,即使私有过程在其所属的类模型中,Me关键字也无法访问它们。

请看以下代码,位于Class1中:

Private Sub Message()
    Debug.Print "Some private procedure."
End Sub

Public Sub DoSomething()
    Me.Message
End Sub

这段代码实例化了一个类的实例:

Sub TestClass()
    Dim objClass As New Class1
    objClass.DoSomething
End Sub

Me.Message 报错 "Method or data member not found."。

如果我将 Private Sub Message() 改成 Public,这个过程就能正常工作。我也可以从 DoSomething 过程中移除 Me 关键字,但是我认为使用 Me 关键字的目的是确保 Class1 的多个实例被正确封装。

为什么 VBA 中的 Me 关键字不能访问其自己模块中的私有过程?在类中省略 Me 关键字并像这样做是否安全?

Private Sub Message()
    Debug.Print "Some private procedure."
End Sub

Public Sub DoSomething()
    Message
End Sub

谢谢!

更新:感谢大家提供正确语法的提示,我的代码正在运行。我仍在寻找一个解释,为什么Me可以在它自己模块的实例中引用私有过程。我找不到任何好的文档。


该问题目前适用于过程,但可以推广到包括所有类型的私有成员:无论是Sub、Function、Property还是Event,都不能使用Me来访问私有成员。 - Sandra Rossi
5个回答

11

不和设计师交流,对为什么会这样设计只能是纯粹猜测。但我的猜测是这样的:Me 关键字返回对当前代码正在执行的对象的引用。我猜想他们没有为 Me 创建一个特殊情况,而是继续遵守对象作用域规则更容易。也就是说 object.method 只能用于公共或友元方法。因此,Me 正是它所说的,当前执行对象的一个实例。既然 VBA/VB6 没有共享方法,那么无论是否使用前缀 Me 都没有关系。

但如果这让你感觉更好,我也觉得这样设计非常讨厌。


2
有道理。似乎“Me”是一个缩写,用于假设创建一个对象变量(Dim Me As Object),并将该变量设置为代码所在的对象(Set Me = ThisModule)。该对象变量仍然可以从外部访问模块属性和过程。谢谢! - Kuyenda

3
在自身类中调用时,你不需要使用Me关键字。

4
除非有阴影 :( - mlvljr

1

我是这个类的对象实例。因此,除了这个类的公共函数或子程序之外,没有人可以直接调用私有子程序或函数或访问私有变量。


1
Public Function Fight() As String
'performs a round of attacks i.e. each character from both sides performs an attack
'returns a scripted version of the outcomes of the round

'check if buccaneers are all dead
If mBuccaneers.aliveCount > 0 Then

    'check if any hostiles are alive
    If mHostiles.aliveCount > 0 Then

        'check we have some buccaneers
        If mBuccaneers.count = 0 Then
            Fight = "There are no buccaneers. Load or create some buccaneers"
        Else
            If mHostiles.count = 0 Then
                'can't fight
                Fight = "There are no hostiles to fight. Generate some hostiles"
            Else
                mScript = ""
                Call GroupAttack(mBuccaneers, mHostiles)
                Call GroupAttack(mHostiles, mBuccaneers)
                Fight = mScript
            End If
        End If

    Else 'hostiles are all dead
        Fight = "Hostiles are all dead. Generate a new set of hostiles"
    End If

Else
    Fight = "Buccaneers are all dead :(. Suggest building or loading a new buccaneer group"
End If
End Function

使用 Call 语句调用私有类方法 GroupAttack。
Private Sub GroupAttack(attackersGroup As clsGroup, defendersGroup As clsGroup)
'implements the attack of one group on another

Dim victimNo As Integer
Dim randomNumber As Integer
Dim attacker As clsCharacter
Dim damage As Integer
Dim defender As clsCharacter
Randomize

For Each attacker In attackersGroup.members

    'check if attacker is still alive
    If attacker.health > 0 Then

        'check if any defenders are still alive because there's no point attacking dead defenders
        If defendersGroup.aliveCount > 0 Then

            'do some damage on a defender
            If defendersGroup.count > 0 Then
                'choose a random hostile
                victimNo = Int(((Rnd() * defendersGroup.aliveCount) + 1))

                'find an alive victim
                memberid = 0
                j = 0
                Do While j < victimNo
                    memberid = memberid + 1
                    If defendersGroup.members(memberid).health > 0 Then
                        j = j + 1
                    End If
                Loop
                'reset our victimno to the live victim
                victimNo = memberid

                damage = defendersGroup.character(victimNo).attack(attacker.strength)

                If damage <> 0 Then  'attacker hit
                    mScript = mScript & attacker.name & " hits " & _
                    defendersGroup.character(victimNo).name & " for " & damage & " damage"

                    If defendersGroup.character(victimNo).health = 0 Then
                        mScript = mScript & " and kills " & defendersGroup.character(victimNo).name
                    End If
                    mScript = mScript & vbCrLf

                Else 'attacker missed
                    mScript = mScript & attacker.name & " missed " & defendersGroup.character(victimNo).name & vbCrLf
                End If

            End If

        End If

    End If

Next attacker   
End Sub

这就是你需要做的,完美运作


0
在COM中,对象实例的类型和对象变量的类型之间存在差异。特别是,对象变量的类型表现为接口类型。每种类型都至少实现一个接口(即它本身),但类型也可以实现其他接口。这种能力用于模拟继承。
在某些框架中,如果类Foo有一个私有成员Bar,则任何非空类型为Foo的变量将持有对包含该成员的某个类对象的引用。该成员可能无法被任何外部代码访问,但它将存在,并且因此可以从Foo的代码中的任何位置访问。
然而,由于COM类变量类型的行为类似于接口而不是可继承类类型,因此不能保证类型为Foo的变量将引用具有Foo的任何非公共成员的对象。虽然编译器可以知道Me将始终引用当前对象,该对象将是实际类型为Foo的对象,但是仅有一个对象可以访问Foo的私有成员,即Me,这意味着编译器没有真正的理由支持基于点的私有成员解引用。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接