Классовые (статические) методы в VBA

36

Интересно, можно ли создавать класс-методы в VBA. По методу класса я имею в виду методы, которые могут быть вызваны без наличия объекта класса. "Статическое" ключевое слово делает этот трюк в С++ и Java.

В приведенном ниже примере я пытаюсь создать статический метод factory.

Пример:

'Classmodule Person'
Option Explicit
Private m_name As String
Public Property Let name(name As String)
    m_name = name
End Property
Public Function sayHello() As String
    Debug.Print "Hi, I am " & m_name & "!"
End Function

'---How to make the following method static?---'
Public Function Create(name As String) As Person
    Dim p As New Person
    p.m_name = name
    Set Create = p
End Function

'Using Person'
Dim p As New Person
p.name = "Bob"
p.sayHello 'Works as expected'
Set p2 = Person.Create("Bob") 'Yields an error'
  • 1
    Это не охватывает суть этого вопроса, а именно методы класса, но разве большинство методов класса не будет охвачено методом, который возвращает ссылку на другой экземпляр класса person? Например, в модуле вы должны иметь: Dim person As new Person: Установить person = person.Create ("Bob"). И метод Create в классе будет выглядеть следующим образом: Открытая функция Create (name As String) As Person: Dim p As Person: Set p = New Person: p.name = name: Set create = p: End Function. Т.е. как только вы инициализировали экземпляр «обработчика» класса, он может быть использован для возврата других экземпляров своего собственного класса.
  • 0
    @Cor_Blimey: Техника, которую вы описываете, наверняка сработает. Однако суть вопроса в том, чтобы уйти, не нуждаясь в «обработчике» экземпляра.
Теги:
static

8 ответов

30
Лучший ответ

Это ( "Public Shared" ) будет работать только в VB.Net.

Невозможно определить методы класса в VBA (или VB). Я бы предложил создать публичную функцию в модуле.

34

1. Создайте нормальный класс, содержащий общедоступный метод (ы), который вам нужно статично

2. Включить общедоступный метод [в этот "статический" класс], который инициализирует [private] "статические поля" внутри класса (он может принимать параметры, если вы пожелаете)

3. Создание модуля действует как factory

Public Function CreateStaticClass(parameters for 'constructor') As StaticClass

    Dim static As StaticClass
    Set static = New StaticClass
    Call StaticClass.Constructor(pass in parameters)
    Set CreateStaticClass = static

End Function

4. теперь вы можете использовать класс "static", вызвав CreateStaticClass ( "параметры" ). MethodName ('parameters') нет необходимости инициализировать экземпляр так, как это делается с помощью метода factory

5. (Необязательно). Если вы хотите принудительно использовать экземпляры singleton, вы можете создать модуль, который будет действовать как контейнер singleton, - включить переменную частного экземпляра и свойство общедоступного доступа. возможно, вы можете использовать установщик 'let', чтобы позволить singleton "заменяться" новым [статическим] классом (используя разные параметры конструктора - см. № 2,3). Используйте "Let" для установщика, поэтому вы можете назначить синглтон без использования "set" ala OO languages ​​

Private curStaticClass as StaticClass

Public Property Get CurrentStaticClass() As StaticClass 

    If curStaticClass Is Nothing Then Set curStaticClass = CreateStaticClass

    Set CurrentStaticClass = curStaticClass  

End Property

Public Property Let CurrentStaticClass(value As StaticClass)

    If Not (curStaticClass Is Nothing) Then Set curStaticClass = Nothing

    Set curStaticClass = value 

End Property

6. Чтобы назначить singleton:

CurrentStaticClass = CreateStaticClass(parameters)

7. Чтобы использовать singleton:

[value = ] CurrentStaticClass.MethodName(parameters)
  • 0
    Я искал, как написать синглтон в Excel VBA. Google привел меня к вашему ответу. Спасибо.
  • 0
    То же самое, спасибо!
Показать ещё 1 комментарий
7

Вы можете попробовать установить атрибут VB_PredeclaredId класса, который должен быть статичным, в True. Это создает экземпляр класса по умолчанию во многом таким же образом, что формы работают в VBA (обратите внимание, что вы можете ссылаться на них напрямую, не создавая экземпляр. Я знаю, что это не лучшая практика, но это возможно).

Это означает, что у вас будет больше одноэлементного стиля, но он может служить вашим требованиям...

Вы не можете установить это непосредственно из самой VBA IDE, однако вы можете выполнить следующие шаги:

1. Экспортировать класс, который вы хотите сделать статичным в папку.

2. Откройте файл .cls, который вы экспортировали в своем любимом текстовом редакторе, и измените   введите VB_PredeclaredId, чтобы он читал VB_PredeclaredId = True.

3. Сохраните файл и повторно импортируйте его в VBA.

Затем вы можете вызвать свои общедоступные методы в классе, не создавая экземпляр класса. Имейте в виду, что метод Initialize вызывается только при первом запуске метода класса/доступа к свойству класса, а метод Terminate никогда не вызывается. Поэтому вы можете написать свой собственный конструктор, а также убедиться, что вы явно вызываете деструктор, если он вам нужен.

Ссылка: Пример Singleton в UtterAccess.com

Ссылка: http://msdn.microsoft.com/en-us/library/ee199159.aspx

  • 4
    Отличное решение и спасибо за точную ссылку на спецификацию VBA. Это заслуживает того, чтобы быть главным ответом, и я думаю, что только позади, потому что это прибывает через 4 года после (в настоящее время) главного ответа. Рекомендую.
  • 2
    Это правильный способ достижения «статического» поведения класса в VBA.
7

Бит в конце дня, но что за черт

В VB6/VBA нет классов или статических методов. Но вы можете объяснять название модуля. У вас не может быть модуль и класс с тем же именем, но вы могли бы назвать его похожим.

Итак, я мог бы иметь класс под названием Employee и модуль под названием EmployeeUtil, а затем я могу написать:

  Dim emp As Employee
  Dim code As String
  Set emp = EmployeeUtil.Create( "Smith", "John", 21-Feb-1988)
  code = "123XY"
  If EmployeeUtil.IsCodeValid( code) Then
    emp.Code = code
  Else
    emp.Code = EmployeeUtil.DefaultCode
  EndIf

Да, значения жестко закодированы, и обработка кода должна, вероятно, находиться под настройщиком свойств, но это не то, что я пытаюсь сделать. EmployeeUtil по существу является владельцем места для членов без экземпляра.

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

3

AFAIK, ближайший вы можете получить (и это не так близко), чтобы использовать "анонимный" экземпляр, так что примерно так:

With New NotReallyStaticClass
    .PerformNotReallyStatic Method, OnSome, Values
End With
2

Свойство экземпляра аналогичного класса доступно для использования в статических классах. Свойство Instancing для этого объекта "GlobalMultUse" должно указывать.

Пример статического класса:

' Error Class in ClassInstancing ActiveDLL project
Option Explicit

Private m_errorID As Integer
Private m_Description As String

Public Property Get ErrorID() As Integer
ErrorID = m_errorID
End Property

Public Property Let ErrorID(ByVal vNewValue As Integer)
m_errorID = vNewValue
End Property

Public Property Get Description() As string
    Description = m_Description
End Property

Public Property Let Description(ByVal vNewValue As string)
    m_Description = vNewValue
End Property

Public Function Error() As Error
    Dim errorInstance As New ClassInstancing.Error

    With errorInstance
        .ErrorID = Me.ErrorID
        .Description = Me.Description
    End With

    Set Error = errorInstance
End Function

Public Sub RaiseError(ByVal pErrorID As Integer, ByVal errorSource As String, ByVal errorDesc As String)
Err.Raise pErrorID, errorSource, errorDesc
End Sub

Public Sub ShowError()
   MsgBox "Error ID: " & CStr(Me.ErrorID) & vbCrLf & _
    "Desc: " & Me.Description
End Sub

Свойство GlobalMultiUse Instancing для указания класса как набора...

Пример использования этого глобального (статического!) класса в другом стандартном проекте EXE:

Private Sub Command1_Click()

    ClassInstancing.Description = "Sample-1 error using !"
    ClassInstancing.ErrorID = 9990

    'Dim multiuseClass As ClassInstancing.Error
    'Set multiuseClass = ClassInstancing.Error

    MsgBox ClassInstancing.Error.ErrorID & vbCrLf & ClassInstancing.Error.Description, vbInformation, "Sample Usage 1"

    ClassInstancing.Description = "Sample-2 error using !"
    ClassInstancing.ErrorID = 1110

    ClassInstancing.ShowError
End Sub

Наконец, заметки в MSDN ((библиотека MSDN Visual Studio 6.0, свойство Instancing)):

GlobalMultiUse. Подобно MultiUse, с одним добавлением: свойства и методы класса могут быть вызваны, как если бы они были просто глобальными функциями. Не обязательно явно создавать экземпляр класса, потому что он будет автоматически создан.

  • 1
    Пожалуйста, исправьте ваше форматирование.
  • 3
    Это доступно только в VB6, но не в VBA.
0

Хотя это не является строго ответом на вопрос, я хотел бы указать, что решение Майка Вудхауса следует избегать. Каждый раз, когда создание нового экземпляра объекта является хитом производительности, и он действительно не решает исходную проблему - он не создает статический объект и не предоставляет также статические методы.

Так как VBA не имеет понятия функций класса, то ближайшим из них может быть использование функций в модулях.

Что касается методов factory, я предлагаю создать модуль со словом factory, добавленным к имени класса, который создает модуль. Что-то вроде:

'Module PersonFactory
Option Explicit

Public Function Create(ByVal sName As String) As Person

    'Code here

End Function

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

-2

вам нужно объявить p2, прежде чем вы сможете использовать Set следующим образом:

dim p2 как Person

Как только вы это сделаете, вы должны заменить оператор Set, используя стандартное назначение: p2 = Person.Create( "Боб" )

В функции: удалите ключевое слово "Установить"... это также может быть источником ошибки.

Я летел слепой, но логически кажется, что это должно сработать. Я новичок в использовании модулей класса в VBA, но они не слишком отличаются от использования свойств VB.Net.

  • 2
    «Я летаю вслепую», так что вы тогда не пробовали.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню