为什么 VBA Me 关键字不能访问自己模块中的私有过程?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1895633/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-11 11:06:01  来源:igfitidea点击:

Why can't the VBA Me keyword access private procedures in its own module?

vbascopeencapsulation

提问by Kuyenda

I just discovered that the Me keyword cannot access private procedures even when they are inside its own class model.

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

Take the following code in Class1:

在 Class1 中取以下代码:

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

Public Sub DoSomething()
    Me.Message
End Sub

This code instantiates an instance of the class:

此代码实例化该类的一个实例:

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

Me.Messagethrows compile error "Method or data member not found."

Me.Message抛出编译错误“未找到方法或数据成员”。

If I change Private Sub Message()to Publicthe procedure works fine. I can also remove the Me keyword from the DoSomething procedure, but I was under the impression that the idea behind the Me keyword is to ensure that multiple instances of Class1 are properly encapsulated.

如果我改变Private Sub Message()Public的程序工作正常。我也可以从 DoSomething 过程中删除 Me 关键字,但我的印象是 Me 关键字背后的想法是确保正确封装 Class1 的多个实例。

Why can't the VBA Me keyword access procedures in its own module when they are private? Is it safe to omit the Me keyword and do something like this in a class?

为什么 VBA Me 关键字在私有时不能访问其自身模块中的程序?省略 Me 关键字并在课堂上做这样的事情是否安全?

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

Public Sub DoSomething()
    Message
End Sub

Thanks!

谢谢!

Update: Thanks for the tips on proper syntax, my code is working. I am still looking for an explanation of whyMe can reference private procedures in an instance of it's own module. I couldn't find any good documentation.

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

采纳答案by Oorang

Any guess as to why it was designed that way would be pure supposition without talking to the designers. But my own guess is this, the Mekeyword returns a reference to the object the code is currently executing in. I would guess rather than create a special case for Me, they found it easier to continue to obey rules of scope for an object. Which is to say object.method can only work on public or friend methods. So Me, is exactly what it says, an instance of an the currently executing object. And since VBA/VB6 doesn't have shared methods, it doesn't really matter if you prefix with Me or not.

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

But if it makes you feel any better, I find it incredibly obnoxious too.

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

回答by Mitch Wheat

You do not need the Mekeyword to call inside own class.

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

回答by Lins

Me is this class object instance. So no one can directly call private subs or functions or access private variables except this class public functions or subs.

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

回答by Bas de Jong

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

Uses the private class method GroupAttack by using the Call statement

通过使用 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

Thats all you need to do ,works like a charm

这就是你需要做的一切,就像一个魅力

回答by supercat

In COM, there's a difference between the types of object instances and the types of object variables. In particular, the types of object variables behave as interface types. Every type implements at least one interface (itself), but types may implement other interfaces as well. Such ability is used to fake inheritance.

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

In some frameworks, if class Foohas a private member Bar, then any non-null variable of type Foowill hold a reference to some class object which contains that member. The member may not be accessible to any outside code, but it will exist, and can thus be accessed from anywhere within the code for Foo.

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

Because COM class-variable types behave like interfaces rather than inheritable class types, however, there's no guarantee that a variable of type Foowill refer to an object which has any of Foo's non-public members. While a compiler could know that Mewill always refer to the present object, which will be of actual type Foo, the fact that the only object upon which a private member of Foocould be accessed is Memeans that there's no real reason for the compiler to support dot-based dereferencing of private members.

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