Есть ли реализованная функция, аналогичная функции toString () в VBA? - PullRequest
0 голосов
/ 15 мая 2019

Я хочу получить объект в коллекции в виде строки без вызова функции для него. например.: В Яве я могу

System.out.print(objVarXY)

и компилятор автоматически вызовет функцию objVarXY.toString () (если реализовано)

в VBA как-то так

Debug.Print parameterListe.LList.Item(1)

приведет к ошибке.

Debug.Print parameterListe.LList.Item(1).toString

будет работать, если я реализовал подфункцию toString. Но что, если я не знаю, какой объект будет в моей коллекции LList?

Ответы [ 2 ]

3 голосов
/ 15 мая 2019

Debug.Print будет неявно пытаться привести указанное значение выражения в String для вывода.

Когда вы Debug.Print объекте, VBA пытается Let -привести объект в значение - если у объекта нет члена по умолчанию , который в конечном итоге дает значение, которое может быть неявно преобразованный в String, тогда вы получите ошибку времени выполнения 438 «объект не поддерживает это свойство или метод», если у класса нет члена по умолчанию .

Если объект представляет собой код пользователя (т. Е. Ваш собственный модуль класса), и если имеет смысл это сделать, вы можете добавить элемент по умолчанию самостоятельно и поручить классу знать, как представлять себя как String (обратите внимание, что атрибут VB скрыт в панелях кода VBE и должен редактироваться вне VBE - если только вы не используете Rubberduck , в этом случае вы можете просто добавить аннотацию @DefaultMember и синхронизировать аннотации / атрибуты):

'@DefaultMember
Public Function ToString() As String
Attribute ToString.VB_UserMemId = 0
    '...
End Function

Но все, что это делает, - это дает классу возможность трактоваться как String посредством неявных вызовов членов. Я бы назвал это чем-то вроде злоупотребления языковой функцией (именно через этот механизм Debug.Print Excel.Application выводит Name приложения или Debug.Print adoConnection выводит свойство ConnectionString соединения), поскольку, как вы заметили, вы также можете просто вызовите этот метод ToString явно.

Если объект не знает, как представить себя как String, тогда что-то где-то придется. В Java (IIRC) и .NET это будет реализация по умолчанию ToString:

Debug.Print TypeName(objVarXY)

... что довольно бесполезно, но по сути это то, что ToString делает по умолчанию.

Независимо от того, пишете ли вы Java, C # или VBA, должен быть код, ответственный за знание того, как представлять objVarXY как String.

К сожалению, VBA не выполняет сопоставление с образцами причудливых штанов, поэтому мы не можем Select Case TypeOf obj как в C # (он только недавно получил эту возможность - не знаю о Java), и, поскольку Select Case TypeName(obj) не будет типом -Безопасно, я бы пошел с If...ElseIf:

Public Function Stringify(ByVal obj As Object) As String
    If TypeOf obj Is Something Then
        Dim objSomething As Something
        Set objSomething = obj ' cast to Something interface
        Stringify = objSomething.SomeProperty

    ElseIf TypeOf obj Is SomethingElse Then
        Dim objSomethingElse As SomethingElse
        Set objSomethingElse = obj ' cast to SomethingElse interface
        Stringify = objSomethingElse.AnotherProperty & "[" & objSomethingElse.Foo & "]"

    'ElseIf TypeOf obj Is ... Then
    '    ...
    Else
        ' we don't know what the type is; return the type name.
        Stringify = TypeName(obj)
    End If
End Function

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

Но, если пользовательские классы предоставляют метод ToString в их интерфейсе по умолчанию , это не идеально: поскольку мы не знаем, какой тип мы получаем из коллекции, все, что у нас есть, это Object и вызов с поздним связыванием - и никакие гарантии времени компиляции, что класс реализует метод ToString, и никакого предупреждения компилятора, если мы попытаемся вызвать, скажем, ToStrnig.

Решение состоит в том, чтобы не поместить ToString в интерфейс классов по умолчанию и формализовать поведение с помощью некоторого модуля класса IString, который может выглядеть следующим образом:

Option Explicit
Public Function ToString() As String
End Funtion

Да, это весь класс.

Теперь пользовательские классы, которые должны быть представлены в виде строк, могут сделать это:

Option Explicit
Implements IString

Private Function IString_ToString() As String
    ' todo: implement the method!
End Function

И теперь мы можем иметь раннюю гарантию, что у объектов есть ToString метод:

Dim o As Object
For Each o In MyCollection
    If TypeOf o Is IString Then
        Dim s As IString
        Set s = o 'cast to IString interface
        Debug.Print s.ToString
    Else
        Debug.Print TypeName(o)
    End If
Next

В конце концов, волшебства нет, независимо от того, какой язык вы используете.

1 голос
/ 15 мая 2019

Что-то подобное не существует в VBA, есть только функции преобразования типов , такие как CStr() для преобразования, например. Integer в String.

Если вам, например, необходимо преобразовать Collection в Array, вам необходимо использовать для этого функцию.


Но что, если я не знаю, какой объект будет внутри моей LList коллекции

Затем вам нужно будет определить, какой это объект (вы, вероятно, ожидаете, например, 5 различных возможных объектов) и сделать что-то вроде Select Case для каждого типа объекта, чтобы преобразовать его в String.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...