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

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

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

Пример:

'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'

person Tom    schedule 28.12.2008    source источник
comment
Это не распространяется на суть этого вопроса, а именно на методы класса, но не будет ли большинство применений метода класса покрываться методом, который возвращает ссылку на другой экземпляр класса человека? например В модуле у вас будет: Dim person Как новый Person: Set person = person.Create(Bob). И метод Create в классе будет выглядеть так: Public Function Create(name As String) As Person: Dim p As Person: Set p = New Person: p.name = name: Set create = p: End Function. т.е. как только вы инициализировали экземпляр обработчика класса, его можно использовать для возврата других экземпляров своего собственного класса.   -  person Cor_Blimey    schedule 15.04.2012
comment
@Cor_Blimey: описанная вами техника наверняка сработает. Однако суть вопроса в том, чтобы обойтись без экземпляра обработчика.   -  person Tom    schedule 27.05.2012


Ответы (8)


Это («общедоступный общий доступ») будет работать только в VB.Net.

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

person Community    schedule 28.12.2008
comment
comment
это возможно - см. ответ от i_saw_drones: stackoverflow.com/a/24574675/1915920 - person Andreas Covidiot; 14.03.2019

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

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

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

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. теперь вы можете использовать «статический» класс, вызвав CreateStaticClass('parameters').MethodName('parameters'). Нет необходимости инициализировать экземпляр, поскольку это делается фабричным методом.

<сильный>5. (Необязательно) Если вы хотите принудительно использовать одноэлементные экземпляры, вы можете создать модуль, который действует как одноэлементный контейнер, включая частную переменную экземпляра и общедоступное свойство доступа. опционально вы можете использовать установщик 'let', чтобы разрешить "замену" синглтона новым [статическим] классом (используя другие параметры конструктора - см. #2,3). Используйте «Let» для установщика, чтобы вы могли назначать синглтон без использования «set» аля языков OO.

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. Чтобы назначить синглтон:

CurrentStaticClass = CreateStaticClass(parameters)

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

[value = ] CurrentStaticClass.MethodName(parameters)
person Matthew Paul Arnold    schedule 16.11.2010
comment
Я искал, как написать синглтон в excel vba. Гугл привел меня к вашему ответу. Спасибо. - person Kim Stacks; 31.03.2012
comment
Итак, если я просто хочу синглтон (инициализация не важна), я использую 5)? - person przemo_li; 20.03.2014
comment
С вашим решением (если я правильно понял) я предлагаю здесь базовый пример того, как определить статический счетчик экземпляров, т.е. + 1 на каждом New. - person Sandra Rossi; 27.09.2020

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

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

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

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

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

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

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

Ссылка: Пример синглтона UtteAccess.com

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

person i_saw_drones    schedule 04.07.2014
comment
Отличное решение и спасибо за точную ссылку на спецификацию VBA. Это заслуживает того, чтобы быть лучшим ответом, и я думаю, что он отстает только потому, что он появился через 4 года после (в настоящее время) лучшего ответа. Я рекомендую. - person S Meaden; 30.06.2017
comment
Это правильный способ добиться «статического» поведения класса в VBA. - person MacroMarc; 01.07.2017

Немного поздно, но какого черта

В 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, назначает параметры через установщики свойств, а затем возвращает экземпляр. Если вы создаете экземпляры объектов во многих местах, это может сэкономить много кода.

person Swanny    schedule 27.08.2009

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

With New NotReallyStaticClass
    .PerformNotReallyStatic Method, OnSome, Values
End With
person Mike Woodhouse    schedule 28.12.2008

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

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

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

'Module PersonFactory
Option Explicit

Public Function Create(ByVal sName As String) As Person

    'Code here

End Function

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

person xxbbcc    schedule 08.09.2011

Свойство экземпляра аналогичного класса доступно для использования в статических классах. Свойство экземпляра для него должно быть указано «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, «Свойство экземпляра»)):

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

person fuat aygan    schedule 07.12.2011
comment
Это доступно только в VB6, но не в VBA. - person i_saw_drones; 03.07.2014

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

тусклый p2 как человек

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

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

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

person Community    schedule 19.02.2009