【问题标题】:Why can't the VBA Me keyword access private procedures in its own module?为什么 VBA Me 关键字不能访问自己模块中的私有过程?
【发布时间】:2009-12-13 05:25:13
【问题描述】:

我刚刚发现 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 抛出编译错误“找不到方法或数据成员。”

如果我将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

谢谢!

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

【问题讨论】:

  • 该问题目前适用于程序,但可以概括为包括所有类型的 private 成员:Me 不能用于访问私人成员,无论是 SubFunctionPropertyEvent

标签: vba scope encapsulation


【解决方案1】:

任何关于它为何设计成这种方式的猜测都是纯粹的假设,无需与设计师交谈。但我自己的猜测是,Me 关键字返回对代码当前正在执行的对象的引用。我猜测与其为Me 创建一个特例,他们发现继续遵守范围规则更容易对于一个对象。也就是说object.method 只能在公共或朋友方法上工作。所以Me,正是它所说的,当前执行对象的一个​​实例。而且由于 VBA/VB6 没有共享方法,所以前缀是否为 Me 并不重要。

但如果它能让你感觉好些,我也觉得它非常令人讨厌。

【讨论】:

  • 有道理。似乎Me 是假设创建一个对象变量(Dim Me As Object)并将该变量设置为代码所在的对象(Set Me = ThisModule)的简写。该对象变量仍然可以从外部访问模块属性和过程。谢谢!
【解决方案2】:

你不需要Me关键字在自己的类中调用。

【讨论】:

  • 除非有阴影:(
【解决方案3】:
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

通过调用语句使用私有类方法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

这就是你需要做的,就像魅力一样工作

【讨论】:

    【解决方案4】:

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

    【讨论】:

      【解决方案5】:

      在 COM 中,对象实例的类型和对象变量的类型是有区别的。特别是,对象变量的类型表现为接口类型。每种类型都至少实现一个接口(本身),但类型也可以实现其他接口。这种能力被用来伪造继承。

      在某些框架中,如果类Foo 有一个私有成员Bar,那么任何Foo 类型的非空变量都将持有对包含该成员的某个类对象的引用。该成员可能无法被任何外部代码访问,但它会存在,因此可以从 Foo 代码中的任何位置访问。

      因为 COM 类变量类型的行为类似于接口而不是可继承的类类型,但是,不能保证 Foo 类型的变量将引用具有 Foo 的任何非公共成员的对象。虽然编译器可以知道Me 将始终引用当前对象,该对象的实际类型为Foo,但可以访问Foo 的私有成员的唯一对象是Me,这意味着编译器没有真正的理由支持基于点的私有成员解引用。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-07-30
        • 1970-01-01
        • 1970-01-01
        • 2013-06-15
        • 2012-09-24
        相关资源
        最近更新 更多