Подтвердить что ты не робот

Обозначение нотации и нотация нот в VBA и MS-Access

Во время просмотра приложения, которое я documenting, я столкнулся с некоторыми примерами нотации банга в доступе к свойствам/методам объектов и т.д. и в в других местах они используют точечную нотацию для того, что похоже на ту же цель.

Есть ли разница или предпочтение в использовании одного или другого? Некоторые простые поисковые запросы раскрывают ограниченную информацию по этому вопросу, когда некоторые люди фактически используют его в противоположных случаях. Возможно, есть раздел стандартов кодирования из MS где-то, что указывает на метод безумия?

4b9b3361

Ответ 1

Несмотря на (ранее) принятый ответ на этот вопрос, удар не является фактически оператором доступа к члену или сборщику. Он делает одну простую и конкретную вещь: Оператор bang обеспечивает доступ к позднему доступу к члену по умолчанию для объекта, передавая буквальное имя, следующее за оператором bang, в качестве строкового аргумента для этого элемента по умолчанию.

Что это. Объект не обязательно должен быть коллекцией. Он не должен иметь метод или свойство, называемое Item. Все, что ему нужно, это Property Get или Function, которые могут принимать строку в качестве первого аргумента.

Более подробную информацию и доказательства см. в моем сообщении в блоге, где обсуждаются следующие вопросы: The Bang! (Exclamation Operator) в VBA

Ответ 2

Оператор bang (!) является сокращением для доступа к членам Collection или другого перечислимого объекта, такого как свойство Fields для ADODB.Recordset.

Например, вы можете создать Collection и добавить к нему несколько ключевых элементов:

Dim coll As Collection
Set coll = New Collection

coll.Add "First Item", "Item1"
coll.Add "Second Item", "Item2"
coll.Add "Third  Item", "Item3"

Вы можете получить доступ к элементу в этой коллекции по его ключу тремя способами:

  • coll.Item("Item2")
    Это наиболее явная форма.

  • coll("Item2")
    Это работает, потому что Item является методом по умолчанию класса Collection, поэтому его можно опустить.

  • coll!Item2
    Это короткая рука для обеих вышеупомянутых форм. Во время выполнения VB6 берет текст после взрыва и передает его в качестве параметра методу Item.

Люди, похоже, делают это более сложным, чем должно быть, поэтому трудно найти простое объяснение. Обычно осложнения или "причины не использовать оператора удара" проистекают из непонимания того, насколько просто он на самом деле. Когда у кого-то есть проблема с оператором bang, они склонны обвинять его вместо реальной причины проблемы, с которой они сталкиваются, что часто бывает более тонким.

Например, некоторые люди рекомендуют не использовать оператор bang для доступа к элементам управления в форме. Таким образом, Me.txtPhone предпочтительнее Me!txtPhone. "Причина" это считается плохим, так как Me.txtPhone будет проверяться на время компиляции для корректности, но Me!txtPhone не будет.

В первом случае, если вы ошибочно вводите код как Me.txtFone и нет контроля с этим именем, ваш код не будет компилироваться. Во втором случае, если вы написали Me!txtFone, вы не получите ошибку компиляции. Вместо этого ваш код взорвется с ошибкой во время выполнения, если он достигнет строки кода, которая использовала Me!txtFone.

Проблема с аргументом против оператора bang заключается в том, что эта проблема не имеет ничего общего с самим оператором bang. Он ведет себя точно так, как предполагалось.

Когда вы добавляете элемент управления в форму, VB автоматически добавляет свойство к вашей форме с тем же именем, что и элемент управления, который вы добавили. Это свойство является частью класса формы, поэтому компилятор может проверять наличие опечаток во время компиляции, если вы получаете доступ к элементам управления с помощью оператора точки ( "." ) (И вы можете получить к ним доступ, используя оператор точки именно потому, что VB создал именованный элемент управления собственность для вас).

Так как Me!ControlName на самом деле кратковременно для Me.Controls("ControlName") 1 не следует удивляться, что вы не получаете никаких проверок времени компиляции против ошибочного ввода имени элемента управления.

Другими словами, если оператор "bang" "плохой", а оператор точки "хорош", вы можете подумать

Me.Controls("ControlName")

лучше, чем

Me!ControlName

потому что первая версия использует точку, но в этом случае точка не лучше, поскольку вы все еще получаете доступ к имени элемента управления с помощью параметра. Это только "лучше", когда есть альтернативный способ написать код, чтобы вы могли проверять время компиляции. Это случается с элементами управления из-за свойств VB, создающих свойства для каждого элемента управления для вас, и именно поэтому Me.ControlName иногда рекомендуется использовать для Me!ControlName.


  • Я изначально заявил, что свойство Controls является свойством по умолчанию класса Form, но Дэвид указал в комментариях, что Controls не является свойством по умолчанию для Form. Фактическое свойство по умолчанию возвращает коллекцию, содержащую содержимое Me.Controls, поэтому кратковременная работа по-прежнему работает.

Ответ 3

Пара getchas служит дополнением к двум исключительным ответам, уже опубликованным:

Доступ к полям набора записей в формах и отчетах
Элемент по умолчанию объектов Form в Access является объединением коллекции элементов управления и набора полей Fields. Если имя элемента управления конфликтует с именем поля, я не уверен, какой объект действительно возвращается. Поскольку свойство по умолчанию как поля, так и элемента управления - это .Value, это часто "различие без разницы". Другими словами, обычно все равно, что это потому, что значения поля и управления часто одинаковы.

Остерегайтесь конфликтов имен!
Эта ситуация усугубляется конструкцией Access Form и Report по умолчанию, чтобы связать с именами те же элементы, что и поле набора записей, к которому они привязаны. Я лично принял соглашение о переименовании элементов управления с их префиксом типа управления (например, tbLastName для текстового поля, связанного с полем LastName).

Не записывать поля записей отчетов!
Ранее я сказал, что элемент по умолчанию объекта Form представляет собой набор элементов управления и полей. Однако объект по умолчанию объекта "Отчет" является только его набором элементов управления. Поэтому, если вы хотите ссылаться на поле набора записей с помощью оператора bang, нужно включить это поле в качестве источника привязанного (скрытого, если нужно) связанного элемента управления.

Остерегайтесь конфликтов с явными свойствами формы/отчета
Когда вы добавляете элементы управления в форму или отчет, Access автоматически создает свойства, относящиеся к этим элементам управления. Например, элемент управления с именем tbLastName будет доступен из модуля кода формы, обратившись к Me.tbLastName. Однако Access не будет создавать такое свойство, если он конфликтует с существующей формой или свойством отчета. Например, предположим, что добавлен элемент управления с именем Pages. Ссылаясь на Me.Pages в модуле кода формы, возвращается свойство Pages Pages, а не элемент управления с именем "Страницы" .

В этом примере можно было явно получить доступ к элементу управления "Страницы" , используя Me.Controls("Pages") или неявно используя оператор bang, Me!Pages. Имейте в виду, однако, что использование оператора bang означает, что Access может вместо этого возвращать поле с именем "Страницы" , если оно существует в наборе записей формы.

Как насчет. Значения?
Хотя это и не упоминалось в этом вопросе, этот вопрос возник в приведенных выше комментариях. Свойство по умолчанию для объектов Field и большинство объектов, привязанных к "данным", - .Value. Поскольку это свойство по умолчанию, оно обычно считается излишне подробным, чтобы всегда включать его явно. Таким образом, это стандартная практика:

Dim EmployeeLastName As String
EmployeeLastName = Me.tbLastName

Вместо:

EmployeeLastName = Me.tbLastName.Value

Остерегайтесь тонкой ошибки. Целом при использовании словарей словаря
Есть случаи, когда это соглашение может вызывать тонкие ошибки. Самое примечательное - и, если память служит, только то, что я фактически натолкнулся на практике, - это использование значения поля/управления в качестве словаря.

Set EmployeePhoneNums = CreateObject("Scripting.Dictionary")
Me.tbLastName.Value = "Jones"
EmployeePhoneNums.Add Key:=Me.tbLastName, Item:="555-1234"
Me.tbLastName.Value = "Smith"
EmployeePhoneNums.Add Key:=Me.tbLastName, Item:="555-6789"

Вероятно, ожидается, что указанный выше код создаст две записи в словаре EmployeePhoneNums. Вместо этого он выдает ошибку в последней строке, потому что мы пытаемся добавить дубликат ключа. То есть, объект tbLastName Control сам является ключом, а не значением элемента управления. В этом контексте контрольное значение даже не имеет значения.

На самом деле, я ожидаю, что адрес памяти объекта (ObjPtr(Me.tbLastName)) вероятен тем, что используется за кулисами для индексации словаря. Я сделал быструю проверку, которая, как представляется, подтверждает это.

'Standard module:
Public testDict As New Scripting.Dictionary
Sub QuickTest()
    Dim key As Variant
    For Each key In testDict.Keys
        Debug.Print ObjPtr(key), testDict.Item(key)
    Next key
End Sub

'Form module:
Private Sub Form_Current()
    testDict(Me.tbLastName) = Me.tbLastName.Value
    Debug.Print ObjPtr(Me.tbLastName); "..."; Me.tbLastName
End Sub

При запуске вышеуказанного кода каждый раз, когда форма закрывается и повторно открывается, добавляется ровно один элемент словаря. Переход от записи к записи (и, таким образом, несколько вызовов в процедуру Form_Current) не добавляет новые словарные элементы, потому что сам объект Control индексирует словарь, а не значение Control.

Мои личные рекомендации/соглашения о кодировании
На протяжении многих лет я применял следующие методы: YMMV:

  • Имена заголовков префикса Form/Report с индикаторами типа управления (например, tbTextBox, lblLabel и т.д.)
  • Обратитесь к элементам Form/Report в коде с использованием обозначения Me. (например, Me.tbLastName)
  • Избегайте создания полей таблицы/запроса с проблемные имена в первую очередь
  • Используйте обозначения Me!, если есть конфликты, например, с устаревшими приложениями (например, Me!Pages)
  • Включить скрытые элементы управления отчетами, чтобы получить доступ к отчетам. Значения полей набора записей
  • Явно включаю .Value только тогда, когда ситуация гарантирует добавленную многословность (например, ключи словаря)

¹ Какое "управляемое данными" управление?
В принципе, элемент управления с свойством ControlSource, например TextBox или ComboBox. Несвязанный элемент управления будет похож на Label или CommandButton. Свойство по умолчанию как TextBox, так и ComboBox - .Value; Ярлыки и CommandButtons не имеют свойства по умолчанию.