Почему ключевое слово VBA Me не может использовать частные процедуры в своем собственном модуле?

Я только что обнаружил, что ключевое слово 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, процедура работает нормально. Я также могу удалить ключевое слово Me из процедуры DoSomething, но у меня сложилось впечатление, что идея ключевого слова Me заключается в том, чтобы убедиться, что несколько экземпляров Class1 правильно инкапсулированы.

Почему процедуры доступа к ключевым словам VBA Me в своем собственном модуле не являются приватными? Можно ли опустить ключевое слово Me и сделать что-то подобное в классе?

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

Public Sub DoSomething()
    Message
End Sub

Спасибо!

Обновление: спасибо за советы по правильному синтаксису, мой код работает. Я все еще ищу объяснение, почему я могу ссылаться на частные процедуры в экземпляре его собственного модуля. Я не мог найти хорошую документацию.

Ответ 1

Любая догадка о том, почему она была разработана таким образом, была бы чистой предпосылкой, не разговаривая с дизайнерами. Но моя собственная догадка заключается в том, что ключевое слово Me возвращает ссылку на объект, в котором в данный момент выполняется код. Я предпочел бы вместо создания специального для Me, им было легче продолжать подчиняться правилам области для объекта. То есть object.method может работать только на общедоступных или дружественных методах. Итак, я, это именно то, что он говорит, экземпляр текущего исполняемого объекта. А поскольку VBA/VB6 не имеет общих методов, на самом деле не имеет значения, префикс ли вы со мной или нет.

Но если это заставляет вас чувствовать себя лучше, я считаю это невероятно неприятным.

Ответ 2

Вам не нужно ключевое слово Me для вызова внутри собственного класса.

Ответ 3

Me - это экземпляр объекта класса. Таким образом, никто не может напрямую обращаться к частным подписчикам или функциям или обращаться к закрытым переменным, кроме общедоступных функций класса или подсетей.

Ответ 4

В COM существует разница между типами экземпляров объектов и типами переменных объекта. В частности, типы переменных объекта ведут себя как типы интерфейсов. Каждый тип реализует хотя бы один интерфейс (сам), но типы могут реализовывать и другие интерфейсы. Такая способность используется для подделки наследования.

В некоторых рамках, если класс Foo имеет частный член Bar, то любая непустая переменная типа Foo будет содержать ссылку на некоторый объект класса, который содержит этот член. Этот член может быть недоступен для любого внешнего кода, но он будет существовать и может быть доступен из любого места в коде для Foo.

Поскольку типы переменных класса COM ведут себя как интерфейсы, а не наследуемые типы классов, однако нет гарантии, что переменная типа Foo будет ссылаться на объект, который имеет любой из Foo непубличных членов. Хотя компилятор мог знать, что Me будет всегда ссылаться на настоящий объект, который будет иметь фактический тип Foo, тот факт, что единственным объектом, доступ к которому может быть доступен частный член Foo, является Me означает что нет никакой реальной причины, чтобы компилятор поддерживал разыменование отдельных членов на основе точек.

Ответ 5

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

Использует метод private класса 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 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

Это все, что вам нужно сделать, работает как шарм