2009-06-29 2 views
4
.

Есть ли способ установить объект в новый экземпляр класса с помощью текстового имени класса?VBA. Создайте новый объект, используя текстовое имя класса

У меня будет библиотека классов, и в зависимости от какой-либо другой переменной я хочу получить один из этих классов во время выполнения.

E.g. У меня есть «CTest1», «CTest2», «CTest3»

я бы функцию, аналогичную ниже

Function GetTestClass(lngClassNo as long) as Object 

Dim strClassName as String  
strClassName = "CTest" & CStr(lngClassNo) 

Set GetTestClass = New instance of class(strClassName) 

End Function 

ответ

4

Там нет никакого отражения в VBA, так что я не думаю, что это возможно. Вы должны были бы сделать что-то вроде следующего, я боюсь:

Function GetTestClass(lngClassNo as long) as Object 

    Select Case lngClassNo 
    Case 1 
     Set GetTestClass = New CTest1 
    Case 2 
     Set GetTestClass = New CTest2 
    ... 

    End Select 

End Function 

Если это не ваши классы CTest определены в COM DLL, в этом случае вы можете использовать оператор CreateObject. Вы должны были бы использовать VB6 создать такой DLL, хотя, вы не можете создавать библиотеки DLL в Excel, Access и т.д. Определение классов

Function GetTestClass(lngClassNo as long) as Object 

    Set GetTestClass = CreateObject("MyDll.CTest" & lngClassNo) 

End Function 
+0

Я думаю, что вы можете столкнуться с проблемами кастинга, если попытаетесь вернуть объект. Вам нужно что-то сделать с интерфейсом COM. – ConcernedOfTunbridgeWells

+0

О, хорошо. Я начал с Select Case, как указано выше, но надеялся на что-то более чистое ... не конец света. Спасибо –

+2

VBA допускает позднее связывание, поэтому, насколько я вижу, проблем с кастингом нет, вам просто нужно быть осторожным, чтобы избежать ошибок времени выполнения, поскольку компилятор не забирает какие-либо опечатки в именах методов и т. Д. –

2

VB действительно определения COM интерфейсов за кулисами, так можно определить данные типы как определение абстрактного интерфейса с конкретными реализациями с использованием ключевого слова implements.

Чтобы получить какой-либо полиморфизм, вы должны это сделать, иначе у вас будут проблемы с литьем. Это немного сложно, но технически возможно сделать это с помощью VB. Если вы хотите копать в нем найти некоторые из продвинутых книг VB Дэн Эпплман или Мэтью Курланд. Я не уверен, что они все еще печатаются, но они, вероятно, доступны через Amazon Marketplace.

Это работает с VB6, и я довольно уверен, что он работает с VBA.

+0

Очень приятно. Это действительно помогает. Приятно иметь возможность использовать компилятор и не беспокоиться о опечатках и т. Д. –

+0

Реализует только то, что вы реализуете все общедоступные методы/свойства данного класса. Как это поможет в создании класса по имени? – Oorang

+1

Создание объекта без проблем. Проблема заключается не в создании класса, а в его использовании. Вы можете использовать Object и позднюю привязку и надеяться на лучшее. Реализует ваш полиморфизм, безопасный для типа. – ConcernedOfTunbridgeWells

0

Возможно, вы сможете сделать это с помощью класса коллекции или массива объектов. Все объекты находятся в одном массиве.

В вашем классе есть свойство .Name и при создании экземпляра этого выполните следующие действия:

Dim CTest() as New CTest 
For n = 1 to 10 
    Redim Preserve CTest(n) 
    CTest(n).Name = "CTest" & CStr(n) 
Next l 

Быстрая и грязная. В приведенном выше примере будет возвращено 10 объектов CTest в одном массиве объектов. Вы также можете вырезать .Name и просто использовать CTest (n).

3

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

Public Function CreateInstance(typeName As String) As Object 
    Dim module As VBComponent 
    Set module = LazilyCreateMPCache() 

    If Not FunctionExists(typeName, module) Then 
     Call AddInstanceCreationHelper(typeName, module) 
    End If 

    Dim instanceCreationHelperName As String 
    instanceCreationHelperName = module.name & ".GetInstanceOf" & typeName 
    Set CreateInstance = Application.Run(instanceCreationHelperName) 
End Function 

Sub AddInstanceCreationHelper(typeName As String, module As VBComponent) 
    Dim strCode As String 
    strCode = _ 
    "Public Function GetInstanceOf" & typeName & "() As " & typeName & vbCrLf & _ 
     "Set GetInstanceOf" & typeName & " = New " & typeName & vbCrLf & _ 
    "End Function" 
    Call AddFunction(strCode, module) 
End Sub 
2

Привет Я знаю, что это старый нить, но если вы все еще нужен ответ смотрите здесь

http://www.codeproject.com/Articles/164036/Reflection-in-VBA-a-CreateObject-function-for-VBA

Он должен ответить на ваш вопрос.

+1

Привет, Пол D, добро пожаловать в переполнение стека и спасибо за добавление ответа. Просто подсказка - всегда лучше для будущей ссылки включать тело решения внутри вашего ответа. Таким образом, если связь когда-либо ломается или перемещается, ваш ответ по-прежнему будет полезен. Благодаря!! – yochannah

+0

Ссылка была очень полезной. В основном назвать метод в стандартном модуле (почти) таким же, как модуль класса. Метод в стандартном модуле возвращает экземпляр модуля класса. Затем выполните 'Set x = Application.Run (" ClassName ")' в вашем основном коде, который запускает метод в стандартном модуле с использованием строки, и, конечно, этот метод возвращает и экземпляр вашего класса в 'x'. Икота - это имя вашего класса, которое должно немного отличаться от имени метода в стандартном модуле. – BarrettNashville

0

CallByName функция может вам помочь. Предположим, в вашем проекте есть несколько модулей классов: clsSample0, clsSample1 и clsSample2. Добавьте новый класс класса с именем clsSpawner, в котором перечислены все целевые классы как общедоступные переменные с одинаковыми именами с e. г.instance_ префикс, и объявил с New ключевым словом:

Public instance_clsSample0 As New clsSample0 
Public instance_clsSample1 As New clsSample1 
Public instance_clsSample2 As New clsSample2 

В модуле добавить Function Spawn() код:

Function Spawn(sClassName) As Object 

    Set Spawn = CallByName(New clsSpawner, "instance_" & sClassName, VbGet) 

End Function 

проверить его с какой-то код, как это:

Sub TestSpawn() 

    Dim objSample0a As Object 
    Dim objSample0b As Object 
    Dim objSample1 As Object 
    Dim objSample2 As Object 

    Set objSample0a = Spawn("clsSample0") 
    Set objSample0b = Spawn("clsSample0") 
    Set objSample1 = Spawn("clsSample1") 
    Set objSample2 = Spawn("clsSample2") 

    Debug.Print TypeName(objSample0a)   ' clsSample0 
    Debug.Print TypeName(objSample0b)   ' clsSample0 
    Debug.Print objSample0a Is objSample0b  ' False 
    Debug.Print TypeName(objSample1)    ' clsSample1 
    Debug.Print TypeName(objSample2)    ' clsSample2 

End Sub 

Как это работает? Spawn функция создает clsSpawner и вызывает экземпляр clsSpawner, чтобы вернуть запрашиваемое свойство, и фактически экземпляр clsSpawner создает новый экземпляр целевого класса из-за объявления с ключевым словом New и возвращает ссылку.

Смежные вопросы