Почему ключевое слово 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
Это все, что вам нужно сделать, работает как шарм