Question

If have got the following definitions of constants:

Protected Const Xsl As String = "Configuration.Xsl"
Protected Const Form As String = "Settings.Form"
Protected Const Ascx As String = "Implementation.Ascx"
...

To fill a dictionary I use this constants as keys:

MyDictionary.Add(Converter.Xsl, "Item 1")
MyDictionary.Add(Converter.Form, "Item 2")
MyDictionary.Add(Converter.Ascx, "Item 3")
...

Now I run throug a loop of XML files and extract the name of the root node:

Dim document As New XmlDocument
document.Load(File.FullName)

Dim rootName As String = document.DocumentElement.Name

The root name matchs with the name of the constant. To get the value of an item from the dictionary I can use something like this:

Select Case rootName.ToUpper
    Case "Xsl".ToUpper
        DictionaryValue = MyDictionary(Class.Xsl)
    Case "Form".ToUpper
        DictionaryValue = MyDictionary(Class.Form)
    Case "Ascx".ToUpper
        DictionaryValue = MyDictionary(Class.Ascx)
    ...
    Case Else
End Select

If a constant is added or removed I also have to change the selection. Is there another way to get the value of a constant? Something like

DictionaryValue = MyDictionary(SomeFunctionToGetConstantValue(rootName))

Thanks for any response.

Was it helpful?

Solution 2

@Clara Onager

My solution I used was the following

Me.GetType.GetField(
    "Xsl",
    Reflection.BindingFlags.NonPublic Or Reflection.BindingFlags.Static Or System.Reflection.BindingFlags.FlattenHierarchy
).GetValue(Nothing)

OTHER TIPS

Try this:

For Each sKey As String In MyDictionary.Keys
    If rootName.Equals(sKey, StringComparison.CurrentCultureIgnoreCase) Then
        DictionaryValue = MyDictionary(sKey)
        Exit For
    End If
Next

At least it will reduce the amount of coding in the select case.

This is a bit of a whopper but I think it provides a pretty elegant solution overall. This is how it is used:

Public Class ConstantsExample

    Public Sub UseConstant()

        Dim value As String = Constants.Types(TypeA)
        Dim category As String = Constants.Categories(General)

    End Sub

End Class

As you can see the code where you use it is as short as it can be made. It does rely on a big pile of source code though:

Public Enum TypeCodes
    <Description("Type A")> TypeA = 0
    <Description("Type B")> TypeB
    <Description("Type C")> TypeC
End Enum

Public Enum CategoryCodes
    <Description("General")> General = 0
    <Description("Specific")> Specific
    <Description("Other")> Other
End Enum

Public NotInheritable Class Constants

#Region "Resources"

    Private Shared myTypes As Dictionary(Of TypeCodes, ConstantItem) = Nothing

    Public Shared ReadOnly Property Types() As Dictionary(Of TypeCodes, ConstantItem)
        Get
            If myTypes Is Nothing Then
                myTypes = New Dictionary(Of TypeCodes, ConstantItem)
                BuildTypes(myTypes)
            End If
            Return myTypes
        End Get
    End Property

    Private Shared Sub BuildTypes(ByRef dict As Dictionary(Of TypeCodes, ConstantItem))
        With dict
            .Add(TypeCodes.TypeA, New ConstantItem(TypeCodes.TypeA.Description, "Type A are..."))
            .Add(TypeCodes.TypeB, New ConstantItem(TypeCodes.TypeB.Description, "Type B are..."))
            .Add(TypeCodes.TypeC, New ConstantItem(TypeCodes.TypeC.Description, "Type C are..."))
        End With
    End Sub

#End Region

#Region "Categories"

    Private Shared myCategories As Dictionary(Of CategoryCodes, ConstantItem) = Nothing

    Public Shared ReadOnly Property Categories() As Dictionary(Of CategoryCodes, ConstantItem)
        Get
            If myCategories Is Nothing Then
                myCategories = New Dictionary(Of CategoryCodes, ConstantItem)
                BuildCategories(myCategories)
            End If
            Return myCategories
        End Get
    End Property

    Private Shared Sub BuildCategories(ByRef dict As Dictionary(Of CategoryCodes, ConstantItem))
        With dict
            .Add(CategoryCodes.General, New ConstantItem(CategoryCodes.General.Description, "General category"))
            .Add(CategoryCodes.Specific, New ConstantItem(CategoryCodes.Specific.Description, "Specific category"))
            .Add(CategoryCodes.Other, New ConstantItem(CategoryCodes.Other.Description, "Other category"))
        End With
    End Sub

#End Region

End Class

Public NotInheritable Class ConstantItem

#Region "Constructors"
    ''' <summary>
    ''' Default constructor.
    ''' </summary>
    Public Sub New()
        'Do nothing
    End Sub
    ''' <summary>
    ''' Simple constructor.
    ''' </summary>
    Sub New(value As String)
        Me.Name = value
        Me.Description = value
    End Sub
    ''' <summary>
    ''' Proper constructor.
    ''' </summary>
    Sub New(name As String, description As String)
        Me.Name = name
        Me.Description = description
    End Sub

#End Region

    Property Name As String
    Property Description As String

    ''' <summary>
    ''' See http://stackoverflow.com/questions/293215/default-properties-in-vb-net
    ''' </summary>
    Public Shared Widening Operator CType(value As String) As ConstantItem
        Return New ConstantItem(value)
    End Operator
    ''' <summary>
    ''' See http://stackoverflow.com/questions/293215/default-properties-in-vb-net
    ''' </summary>
    Public Shared Widening Operator CType(value As ConstantItem) As String
        Return value.Name
    End Operator

End Class

Note the use of the Widening Operator to dispense with having to type .Item. If you'd rather not use the Widening Operator then simple comment that bit out and change Constants.Types(TypeA) to Constants.Types.Item(TypeA).

This is the Description Extension you may need:

Public Module Extensions
    Private Enum SampleDescription
        <Description("Item One")> ItemOne = 1
        <Description("Item Two")> ItemTwo = 2
        <Description("Item Three has a long description")> ItemThree = 3
    End Enum
    ''' <summary>
    ''' This procedure gets the description attribute of an enum constant, if any. Otherwise it gets 
    ''' the string name of the enum member.
    ''' </summary>
    ''' <param name="value"></param>
    ''' <returns></returns>
    ''' <remarks>Usage:  myenum.Member.Description()
    ''' Add the Description attribute to each member of the enumeration.</remarks>
    <Extension()> _
    Public Function Description(ByVal value As [Enum]) As String
        Dim fi As Reflection.FieldInfo = value.GetType().GetField(value.ToString())
        Dim aattr() As DescriptionAttribute = DirectCast(fi.GetCustomAttributes(GetType(DescriptionAttribute), False), DescriptionAttribute())
        If aattr.Length > 0 Then
            Return aattr(0).Description
        Else
            Return value.ToString()
        End If
    End Function

End Module

And these are the Imports statements I used (the Assembly is called MyPatterns):

Imports System.ComponentModel
Imports MyPatterns.TypeCodes
Imports MyPatterns.CategoryCodes

Importing the two 'codes' allows you to do without the prefix for the Enum which shortens the code.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top