4
\$\begingroup\$

This is to be used like an Enum (as parameter mostly), but for string

(Using .NET 3.5)

Actual implementation:

Public MustInherit Class StringEnum(Of T As {New, StringEnum(Of T)})
    Private Shared ReadOnly _lock As New Object
    Private Shared ReadOnly _cache As New Dictionary(Of String, T)

    Private _value As String

    Public ReadOnly Property Value() As String
        Get
            Return _value
        End Get
    End Property

    Friend Sub New()
    End Sub

    Public Shared Function GetEnum(value As String) As T
        Dim se As T = Nothing

        If Not _cache.TryGetValue(value, se) Then
            Return Nothing
        End If

        Return se
    End Function

    Public Overrides Function Equals(obj As Object) As Boolean
        Return obj IsNot Nothing AndAlso String.Equals(_value, DirectCast(obj, T)._value, StringComparison.Ordinal)
    End Function

    Public Overrides Function GetHashCode() As Integer
        Return _value.GetHashCode
    End Function

    Public Overrides Function ToString() As String
        Return _value
    End Function

    Public Shared Widening Operator CType(ByVal se As StringEnum(Of T)) As String
        Return se.Value
    End Operator

    Public Shared Operator =(se1 As StringEnum(Of T), se2 As StringEnum(Of T)) As Boolean
        Return Object.Equals(se1, se2)
    End Operator

    Public Shared Operator <>(se1 As StringEnum(Of T), se2 As StringEnum(Of T)) As Boolean
        Return Not (se1 = se2)
    End Operator

    Friend Shared Function CacheHelper(value As String) As T
        Dim se As T = Nothing

        SyncLock _lock
            If Not _cache.TryGetValue(value, se) Then
                se = New T()
                se._value = value
                _cache.Add(se.Value, se)
            End If
        End SyncLock

        Return se
    End Function
End Class

Public Class ValueStringEnum
    Inherits StringEnum(Of valueStringEnum)

    Public Shared ReadOnly Property Value1() As valueStringEnum
        Get
            Return CacheHelper("Value 1")
        End Get
    End Property

    Public Shared ReadOnly Property Value2() As valueStringEnum
        Get
            Return CacheHelper("Value 2")
        End Get
    End Property

    Public Shared ReadOnly Property Value3() As valueStringEnum
        Get
            Return CacheHelper("Value 3")
        End Get
    End Property

    Public Shared ReadOnly Property Value4() As valueStringEnum
        Get
            Return CacheHelper("Value 4")
        End Get
    End Property

    'these 3 below are annoying but can't easily reuse the one in base class
    Public Overrides Function Equals(obj As Object) As Boolean
        Return MyBase.Equals(obj)
    End Function

    Public Overrides Function GetHashCode() As Integer
        Return MyBase.GetHashCode
    End Function

    Public Overrides Function ToString() As String
        Return MyBase.ToString
    End Function
End Class

Testing the implementation:

Module Module1
    Sub Main()
        Dim v1 As ValueStringEnum = ValueStringEnum.Value1
        Dim v2 As ValueStringEnum = ValueStringEnum.Value2
        Dim v3 As ValueStringEnum = ValueStringEnum.Value3
        Dim v4 As ValueStringEnum = ValueStringEnum.Value4

        Dim vS1 As String = v1
        Dim vS2 As String = v2
        Dim vS3 As String = v3
        Dim vS4 As String = v4

        Dim vc1 As ValueStringEnum = ValueStringEnum.GetEnum(vS1)
        Dim vc2 As ValueStringEnum = ValueStringEnum.GetEnum(vS2)
        Dim vc3 As ValueStringEnum = ValueStringEnum.GetEnum(vS3)
        Dim vc4 As ValueStringEnum = ValueStringEnum.GetEnum(vS4)

        test(v4) 'print Value 4

        test(ValueStringEnum.Value2) 'print Value 2

        Console.WriteLine("vc4.equals(v4) " & vc4.Equals(v4)) 'true
        Console.WriteLine("vc4.equals(v2) " & vc4.Equals(v2)) 'false

        Console.WriteLine("vc4 = v4 " & (vc4 = v4)) 'true
        Console.WriteLine("vc4 = v2 " & (vc4 = v2)) 'false


        Console.WriteLine("vc4 <> v4" & (vc4 <> v4)) 'false
        Console.WriteLine("vc4 <> v2 " & (vc4 <> v2)) 'true

        Console.WriteLine("vc4 = Value 4 " & (vc4 = "Value 4")) 'true
        Console.WriteLine("vc4 = Value 2 " & (vc4 = "Value 2")) 'false


        Console.WriteLine("vc4 <> Value 4 " & (vc4 <> "Value 4")) 'false
        Console.WriteLine("vc4 <> Value 2" & (vc4 <> "Value 2")) 'true
    End Sub

    Sub test(value As ValueStringEnum)
        Console.WriteLine(value)
    End Sub
End Module

Can you spot anything wrong or missing or a possible improvement?

\$\endgroup\$
3
  • \$\begingroup\$ this is an updated version of the code of my preview question that i deleted \$\endgroup\$
    – Fredou
    May 25, 2016 at 18:59
  • 1
    \$\begingroup\$ I would strongly recommend not deleting your unanswered posts in the future - simply edit them with the updated code; it's fine as long as there are no answers. \$\endgroup\$ May 25, 2016 at 19:25
  • 1
    \$\begingroup\$ Not sure it would be an answer to this ; but you could use the completionlist xml documentation tag to "transform" any class in an Enum-like type but maybe that deviates too much from the current topic. \$\endgroup\$
    – Sehnsucht
    Jul 8, 2016 at 23:19

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Browse other questions tagged or ask your own question.