#vba
Вопрос:
У меня есть несколько пользовательских типов и функция для каждого, которая принимает эти типы и что-то с ними делает.
Дело в том, однако, что я хотел бы написать одну универсальную функцию, которая принимает любой из этих типов, а затем просто использует TypeName
, чтобы выяснить, какой это тип, и обрабатывает его так, как ему нужно.
Как мне это сделать? Я попытался принять параметр как Function Foo(Param As Object)
, но затем он терпит неудачу, когда я пытаюсь передать в функцию определяемый пользователем тип.
Комментарии:
1. Использование
variant
подойдет2. Только этого не произойдет. Обратите внимание, что
TypeName
на UDT тоже нельзя использовать.
Ответ №1:
Определяемые пользователем типы (UDT) не являются классами (они похожи Structures
на C или Records
на Pascal), поэтому экземпляры UDT не являются объектами — вот причина, по которой вы не можете использовать их в качестве аргумента своей функции foo
.
VBA имеет универсальный тип данных Variant
. Поэтому , когда у вас есть Function Foo(Param As Variant)
, вы можете передать функции все, что угодно, Foo 3
или Foo ActiveSheet
или Foo "Hello world"
. Что угодно, кроме УДТ… Если вы попытаетесь это сделать, вы получите сообщение об ошибке компилятора, в котором говорится: «Только пользовательские типы, определенные в модулях общедоступных объектов, могут быть принудительно добавлены к варианту или из него или переданы функциям с поздней привязкой».:
Public Type tMyType
i As Integer
s As String
End Type
Sub Test
Dim bar as tMyType
' Compiler complains
foo bar
Dim myUniversalVariant as Variant
' Compiler complains also
myUniversalVariant = bar
End Sub
В официальной документации Variant
говорится, что «Типы вариантов теперь поддерживают пользовательские типы»., однако, по крайней мере, в Excel 2016 это не работает (или, по крайней мере, я не смог этого сделать).
Ваш лучший выбор — использовать классы. Если вам лень, просто создайте модуль класса (для каждого типа) и поместите всех членов типа в качестве общедоступных членов, больше ничего не нужно (я не буду начинать описывать плюсы и минусы геттера и сеттера). Вам просто нужно помнить, что теперь вы должны использовать инструкцию New для создания и установки для назначения экземпляра.
В модуле класса (я назвал его clsMyType
):
public i As Integer
public s As String
В обычном модуле:
Sub Test
Dim bar as clsMyType
Set bar = new clsMyType
foo bar
Dim myUniversalVariant as Variant
Set myUniversalVariant = bar
foo myUniversalVariant
End Sub
Теперь в зависимости от того, хочет ли ваша функция получать только объект или другие данные (например, целые числа или строки), типом параметра может быть Вариант или объект
Function foo(Param as Object)
Debug.Print TypeName(Param)
End Function