VBA - Создать новый объект, используя текстовое имя класса - PullRequest
5 голосов
/ 29 июня 2009

Есть ли способ установить объект для нового экземпляра класса, используя текстовое имя класса?

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

например. У меня есть "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

Ответы [ 6 ]

4 голосов
/ 29 июня 2009

В 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
3 голосов
/ 28 января 2011

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

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 голосов
/ 08 января 2014

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

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

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

2 голосов
/ 29 июня 2009

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

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

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

0 голосов
/ 22 января 2018

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 и возвращает ссылку.

0 голосов
/ 01 июля 2009

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

В вашем классе есть свойство .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).

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