Reputation: 555
I am trying to make a complex class with following structure:
Obj {
name {
value = ""
tag = "name"
}
id {
value = ""
tag = "id"
}
address {
value = ""
tag = "address"
}
}
First I created a RefPair
class that looks like this:
Public tag As String
Public value As String
Then a LawSubject
class that looks like this:
Public name As New RefPair
name.tag = "name"
Public id As New RefPair
id.tag = "id"
Public address As New RefPair
address.tag = "address"
When I try to call this class I get an error on name.tag = "name"
string: compile error: invalid outside procedure
What am I getting wrong?
Upvotes: 0
Views: 75
Reputation: 601
What you need is a Parent object LawSubject
to hold references to a child object RefPair
. The implementation closest to your example in (which I think is C++
?) would be the following:
Class: RefPair
Option Explicit
Private Type TRefPair
Tag As String
Value As String
End Type
Private this As TRefPair
Public Property Let Tag(ByVal Value As String)
this.Tag = Value
End Property
Public Property Get Tag() As String
Tag = this.Tag
End Property
Public Property Let Value(ByVal Value As String)
this.Value = Value
End Property
Public Property Get Value() As String
Value = this.Value
End Property
Class: LawSubject
Option Explicit
Private Type TLawSubject
Name As New RefPair
Id As New RefPair
Address As New RefPair
End Type
Private this As TLawSubject
Public Property Get Name() As RefPair
Set Name = this.Name
End Property
Public Property Get Id() As RefPair
Set Id = this.Id
End Property
Public Property Get Address() As RefPair
Set Address = this.Address
End Property
Usage:
Option Explicit
Sub Testing()
Dim LwSbjct As LawSubject
Set LwSbjct = New LawSubject
LwSbjct.Address.Tag = "Address Tag"
LwSbjct.Address.Value = "Address Value"
LwSbjct.Name.Tag = "Name Tag"
LwSbjct.Name.Value = "Name Value"
LwSbjct.Id.Tag = "Id Tag"
LwSbjct.Id.Value = "Id Value"
Debug.Print LwSbjct.Address.Tag
Debug.Print LwSbjct.Address.Value
Debug.Print LwSbjct.Name.Tag
Debug.Print LwSbjct.Name.Value
Debug.Print LwSbjct.Id.Tag
Debug.Print LwSbjct.Id.Value
End Sub
Immediate Window Results:
Upvotes: 0
Reputation: 8531
There is also a way using a dictionary, maybe overkill, but gives the ability to add new data pairs on the fly.
A class as so
Public Extract As Scripting.Dictionary
Private Sub Class_Initialize()
Set Extract = New Scripting.Dictionary
AddDefault "Name", "1"
AddDefault "ID", "2"
AddDefault "Address", "3"
End Sub
Private Sub Class_Terminate()
Set Extract = Nothing
End Sub
Public Function AddToExisting(strKey As String, _
strContentsKey As String, _
strContentsValue As String)
Extract(strKey).Add strContentsKey, strContentsValue
End Function
Private Function AddDefault(strKey As String, strValue As String)
Extract.Add strKey, CreateKeyValuePair(strKey & " Tag", strValue)
End Function
Private Function CreateKeyValuePair( _
strKey As String, _
strValue As String) As Scripting.Dictionary
Dim dicTemp As New Scripting.Dictionary
With dicTemp
.Add "Tag", strKey
.Add "Value", strValue
End With
Set CreateKeyValuePair = dicTemp
End Function
Then used like so
Sub testComplex()
Dim c As New clsComplex
Debug.Print c.Extract("Name")("Tag")
Debug.Print c.Extract("Name")("Value")
c.AddToExisting "ID", "Date of Value", CStr(Date)
c.AddToExisting "ID", "Date of Value Check", CStr(Date + 20)
Debug.Print c.Extract("ID")("Tag")
Debug.Print c.Extract("ID")("Value")
Debug.Print c.Extract("ID")("Date of Value")
Debug.Print c.Extract("ID")("Date of Value Check")
c.AddToExisting "Address", "Address Proof", "Utility Bill"
Debug.Print c.Extract("Address")("Tag")
Debug.Print c.Extract("Address")("Value")
Debug.Print c.Extract("Address")("Address Proof")
Set c = Nothing
End Sub
Upvotes: 0
Reputation: 94
You are trying to set an object's property, which in VBA is only possible inside a procedure. (Sub, Function, or Property)
In alternative, you can move your property let statements to the Class_Initialize
procedure:
Public name As New RefPair
Public id As New RefPair
Public address As New RefPair
Private Sub Class_Initialize()
name.tag = "name"
id.tag = "id"
address.tag = "address"
End Sub
But may I suggest you shouldn't be using a class module for storing 2 string values? The overhead is enormous. Instead, consider using Type:
Private Type RefPairType
tag As String
value As String
End Type
Private Name As RefPairType
Private Id As RefPairType
Private Address As RefPairType
Private Sub Class_Initialize()
Name.tag = "name"
Id.tag = "id"
Address.tag = "address"
End Sub
This way, you can encapsulate the relevant data for your class, while achieving better control over the process of manipulating the internal values from the outside, by providing property accessors. For example:
Private Type RefPairType
tag As String
value As String
End Type
Private Type LawSubjectType
Name As RefPairType
Id As RefPairType
Address As RefPairType
End Type
Private This As LawSubjectType
Private Sub Class_Initialize()
With This
.Name.tag = "name"
.Id.tag = "id"
.Address.tag = "address"
End With
End Sub
' Allow outside code to get the value of the Name pair
Public Property Get NameValue() As String
NameValue = This.Name.value
End Property
' Allow outside code to get the value of the ID pair
Public Property Get IdValue() As String
IdValue = This.Id.value
End Property
' Allow outside code to get and modify the value of the Address pair
Public Property Get AddressValue() As String
AddressValue = This.Address.value
End Property
Public Property Let AddressValue(val As String)
This.Address.value = val
End Property
Upvotes: 4