A Type
- это не класс или объект. Это немного больше, чем кусок памяти с определенной раскладкой. Если у вас есть что-то, на что у вас есть экземпляр, который вы можете New
поднять, то вам нужен не Type
, а модуль класса. Определяемые пользователем типы имеют много ограничений, из-за которых с ними довольно сложно работать, по крайней мере, с точки зрения ООП.
В этом случае вы хотите, чтобы ValueTagPair
или что-то могло выглядеть следующим образом - обратите внимание, как Private Type
все еще может использоваться для хранения состояния экземпляра в одном частном поле (this
):
Option Explicit
Private Type TPair
Value As String
Tag As String
End Type
Private this As TPair
Public Property Get Value() As String
Value = this.Value
End Property
Public Property Let Value(ByVal rhs As String)
this.Value = rhs
End Property
Public Property Get Tag() As String
Tag = this.Tag
End Property
Public Property Let Tag(ByVal rhs As String)
this.Tag = rhs
End Property
Теперь вы можете объявить любую переменную As ValueTagPair
и использовать ее как таковую, включаятип возврата члена Property
в другом классе.
Option Explicit
Private Type TSomething
Name As ValueTagPair
Id As ValueTagPair
End Type
Private this As TSomething
Public Property Get Name() As ValueTagPair
Set Name = this.Name
End Property
Public Property Get Id() As ValueTagPair
Set Id = this.Id
End Property
Private Sub Class_Initialize()
Set this.Name = New ValueTagPair
Set this.Id = New ValueTagPair
End Sub
Теперь предположим, что это класс Something
, теперь мы можем сделать это:
Dim thing As Something
Set thing = New Something
thing.Name.Tag = "name-tag"
thing.Name.Value = "name-value"
thing.Id.Tag = "id-tag"
thing.Id.Value = "id-value"
Если вам нужнобыть в состоянии сделать Set thing.Name = New ValueTagPair
, тогда вам нужно будет выставить Public Property Set
член для свойства Name
.
Означает ли это, что я должен делать геттеры / сеттеры длякаждая переменная-член класса?
Да. Открытые члены класса определяют интерфейс этого класса, а интерфейс определяет, как можно использовать объект. Если Class1.Name
не отображается на интерфейсе Class1
, то он не существует;использование с ранней привязкой не будет компилироваться, а вызовы с поздней привязкой (т.е. вызовы, сделанные против Object
или Variant
) будут взорваны во время выполнения с ошибкой 438.
Что если мой класс в 10 раз больше?
Тогда у него, вероятно, слишком много обязанностей. Объекты с ясной и четко определенной целью обычно не выполняют 20 задач.