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
В конце концов, волшебства нет, независимо от того, какой язык вы используете.