Thursday 16 May 2019

VBA - Enumeration to strings

It has been asked on Stack Overflow is there is an inbuilt way to convert a VBA enum to a string, i.e. to get a string representation of the value, like there is in C#. The answer is no. But one can write a helper function with the enum values stored in an array. (UPDATE: and in this follow-up post I give Python code to write it for you!)

In the code below I have four examples. In the first two the values are sequential, they differ only in that one is zero-based and the other isn't.

The third example is a binary flag based enumeration where the values are not mutually exclusive but instead building blocks for a composite indicator. This requires a helper function to convert the value to binary with modular division.

The fourth example is to catch all other cases because it uses a Switch statement to find the index of the correct string in the array and is less efficient.

However, all three examples require the enumeration definition to be synchronized to the array of strings. This might be considered a pain, I wonder if there is anything we can do to salve this pain?

Option Explicit

'* a sequential example zero based
Public Enum Cars
    BMW
    Ford
    Lotus
End Enum

'* a sequential example non-zero based
Public Enum MyColor
    Red = 1
    Green
    Blue
End Enum

'* a binary flag based
Public Enum ParamFlags
    FIN = 1
    FOUT = 2
    FLCID = 4
    FRETVAL = 8
    FOPT = 16
    FHASDEFAULT = 32
    FHASCUSTDATA = 64
End Enum

'* non sequential, non binary flags
Public Enum PrimeNumbers
    First = 2
    Second = 3
    Third = 5
    Fourth = 7
    Fifth = 11
End Enum

Public Function CarsEnumToString(e As Cars)
    CarsEnumToString = Array("BMW", "Ford", "Lotus")(e)
End Function

Public Function MyColorEnumToString(e As MyColor)
    MyColorEnumToString = Array("Red", "Green", "Blue")(e - 1)
End Function

Public Function ParamFlagsEnumToString(e As ParamFlags)
    ParamFlagsEnumToString = ToBinary(e, Array("FIN", "FOUT", "FLCID", "FRETVAL", "FOPT", "FHASDEFAULT", "FHASCUSTDATA"))
End Function

Public Function PrimeNumbersEnumToString(e As PrimeNumbers) As String
    PrimeNumbersEnumToString = Array("First", "Second", "Third", "Fourth", "Fifth")(Switch(e = 2, 0, e = 3, 1, e = 5, 2, e = 7, 3, e = 11, 4))
End Function


Function ToBinary(ByVal lFlags As Long, ByRef vNames As Variant)
    Dim dic As Scripting.Dictionary
    Set dic = New Scripting.Dictionary

    Dim lIndex As Long

    While lFlags > 0
        If lFlags Mod 2 = 1 Then dic.Add dic.Count, vNames(lIndex)
        
        lFlags = lFlags \ 2
        lIndex = lIndex + 1
    Wend
        
    ToBinary = VBA.Join(dic.Items, " | ")
End Function

Sub Test()
    Debug.Assert CarsEnumToString(BMW) = "BMW"
    Debug.Assert CarsEnumToString(Ford) = "Ford"
    Debug.Assert CarsEnumToString(Lotus) = "Lotus"

    Debug.Assert MyColorEnumToString(Red) = "Red"
    Debug.Assert MyColorEnumToString(Green) = "Green"
    Debug.Assert MyColorEnumToString(Blue) = "Blue"

    Dim e As ParamFlags
    e = FIN + FOUT + FLCID + FOPT + FHASDEFAULT + FHASCUSTDATA

    Debug.Assert ParamFlagsEnumToString(e) = "FIN | FOUT | FLCID | FOPT | FHASDEFAULT | FHASCUSTDATA"

    Debug.Assert PrimeNumbersEnumToString(2) = "First"
    Debug.Assert PrimeNumbersEnumToString(11) = "Fifth"

End Sub

No comments:

Post a Comment