Jook
Jook

Reputation: 4692

Is it possible to change the type of a variable or function in VBA during runtime?

I am riddling about if it is possible to conditionally switch the type of a function or variable between enum types.

Something like this:

Public Enum enmTest
  eA = 1
  eB = 2
  eC = 3
End Enum

Public Enum enmDemo
  eA = 10
  eB = 50
  eC = 100
End Enum

Public Function demoFunction() as enmDemo
  Dim eDemo as enmDemo
  ReDim eDemo as enmTest
  ReDim demoFunction as enmDemo          
End Function

'this does not work, but is there no way to make this work?
Public Sub test()
  debug.print demoFunction().eA 'should be 1
End Sub

'this does not work, but is there no way to make this work?
Public Sub test2
  Dim temp as Variant
  temp = demoFunction()
  debug.print temp.eB 'should be 2
End Sub

Basically the goal is to have a variable like Dim myVar which might be an enumA or enumB type. These enums might be identicall, except their values.

My guess is this won't work at no angle, because of the way VBA handles enums. But just to make sure I would like to get an explanation, as I only have a gut feeling after an hour of experimenting.


My current workaround, which hopefully demonstrates my goal:

Public Enum enmTest
  eA = 1
  eB = 2
  eC = 3
End Enum

Public Enum enmDemo
  eA = 10
  eB = 50
  eC = 100
End Enum

Public Function demo()
  Debug.Print Str(getValues(1)(1))   'prints 1
  Debug.Print Str(getValues(2)(1))   'prints 10
End Function

Public Function getArray(val1, val2, val3) as Variant
  Dim result as Variant
  ReDim result(1 to 3)
  result(1) = val1
  result(2) = val2
  result(3) = val3
  getArray = result
End Function

Public Function getValues(myInt as Integer) as Variant
  If (myInt = 1) Then
    getValues = getArray(enmDemo.eA, enmDemo.eB, enmDemo.eC)
  Else
    getValues = getArray(enmTest.eA, enmTest.eB, enmTest.eC)        
  End If
End Function

Upvotes: 1

Views: 4137

Answers (2)

alexanderbird
alexanderbird

Reputation: 4228

I know we're half a year later now, but in case someone else finds this...

You could also achieve what you're looking for with classes and interfaces (using the implements keyword) instead of enumerations. It's a little more verbose than enumerations, but it's not as clunky as the conversion options, I think. If you have to use enums for some reason not included in the question, then this doesn't solve your problem. But, if you're just using the enum as a collection of named variable with numeric values, then this should do the trick:

In short, you define an interface (a class) with public read only members for eA, eB, and eC. This spells out what properties each interchangeable "enum" (class) must have.

interface:

' In a class module called IEnm
Public Property Get eA() As Long
End Property

Public Property Get eB() As Long
End Property

Public Property Get eC() As Long
End Property

Then you write another class for each specific "enum" that you're looking for - enmTest and enmDemo. These define the values of each property.

enmTest:

' In a class module called enmTest
Implements IEnm 'promises that this class defines each required property

Public Property Get IEnm_eA() As Long
    IEnm_eA = 1
End Property

Public Property Get IEnm_eB() As Long
    IEnm_eB = 2
End Property

Public Property Get IEnm_eC() As Long
    IEnm_eC = 3
End Property

enmDemo:

' In a class module called enmDemo
Implements IEnm

Public Property Get IEnm_eA() As Long
    IEnm_eA = 10
End Property

Public Property Get IEnm_eB() As Long
    IEnm_eB = 50
End Property

Public Property Get IEnm_eC() As Long
    IEnm_eC = 100
End Property

Here's a demo of how to use it.

Private actsLikeAnEnum As IEnm ' doesn't care if its enmTest, enmDemo, 
' or enmSomethingElse

Public Function demoFunction() As IEnm ' you don't know what you'll get out
  'Dim eDemo As enmDemo
  'ReDim eDemo as enmTest
  'ReDim demoFunction as enmDemo
  Set actsLikeAnEnum = New enmTest 
  Set demoFunction = actsLikeAnEnum ' you could just return a new enmTest, 
  ' but I wanted to show that the single IEnm typed variable (actsLikeAnEnum) can 
  ' store both enmTest type objects and enmDemo type objects
End Function

Public Sub test()
  Debug.Print demoFunction().eA 'prints 1
End Sub

Public Sub test2()
  Dim temp As Variant
  ' since IEnm is an object, need to use the Set keyword
  Set temp = demoFunction()
  Debug.Print temp.eB 'prints 2
End Sub

'Or, if you want it to return 10 and 50....
Public Function demoFunctionTwo() As IEnm
    Set actsLikeAnEnum = New enmDemo
    Set demoFunctionTwo = actsLikeAnEnum
End Function

Public Sub test3()
  Debug.Print demoFunctionTwo().eA 'prints 10
End Sub

Public Sub test4()
  Dim temp As Variant
  Set temp = demoFunctionTwo()
  Debug.Print temp.eB 'prints 50
End Sub

You can set actsLikeAnEnum (which is an IEnm type object) to either a new enmDemo or an enmTest because they both implement IEnm. Then you can use actsLikeAnEnum without knowing whether there happens to be an enmDemo object or an enmTest object stored in the variable.

Upvotes: 0

chris neilsen
chris neilsen

Reputation: 53166

The best I can offer is a custom conversion Function for each Enum type. Although I would echo Dans comment: consider carefully why you want this.

' write one of these for each conversion you want
Function CastToDemo(ByRef v As enmTest) As enmDemo
    Select Case v
        Case enmTest.eA
            CastToDemo = enmDemo.eA
        Case enmTest.eB
            CastToDemo = enmDemo.eB
        Case enmTest.eC
            CastToDemo = enmDemo.eC
    End Select
End Function

' Use like this
Public Sub test()
    Dim a As enmTest
    Dim b As enmDemo

    a = enmTest.eA

    b = CastToDemo(a)

    Debug.Print b
End Sub

Upvotes: 1

Related Questions