VB.NET:获取常量的动态值

3
如果您有以下常量定义:

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

为了填充字典,我使用以下常量作为键:

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

现在我正在循环遍历一系列XML文件,并提取根节点的名称:
Dim document As New XmlDocument
document.Load(File.FullName)

Dim rootName As String = document.DocumentElement.Name

根名称与常量的名称匹配。要从字典中获取项的值,可以使用以下方法:

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

如果添加或删除常量,我还必须更改选择。有没有另一种获取常量值的方法?例如:
DictionaryValue = MyDictionary(SomeFunctionToGetConstantValue(rootName))

谢谢回复。

1
请参考http://stackoverflow.com/questions/1456518/how-to-obtain-a-list-of-constants-in-a-class-and-their-values?rq=1获取常量列表及其值的示例。然后,请参考https://dev59.com/0UjSa4cB1Zd3GeqPKPxa#1308604以获得更简洁的仅查找常量的示例。另一方面,您真的需要将它们作为单独的常量吗?您可以跳过常量,只使用字典吗? - Abraham
我通过这两个链接的帮助解决了它。感谢。我使用常量是因为该过程分为两个程序集。常量定义和字典分析包含在一个MustInherit类中,在另一个程序集中,该类被继承并且字典被填充了值。为避免多次编写值,我使用这些常量。 - mburm
3个回答

2

@Clara Onager

我使用的解决方案如下:

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

2

这是一个有点庞大的东西,但我认为它总体上提供了一个相当优雅的解决方案。以下是它的使用方法:

Public Class ConstantsExample

    Public Sub UseConstant()

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

    End Sub

End Class

正如您所见,使用它的代码尽可能地短小。但是它确实依赖于大量源代码:

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 https://dev59.com/lXVC5IYBdhLWcg3wcgqd
    ''' </summary>
    Public Shared Widening Operator CType(value As String) As ConstantItem
        Return New ConstantItem(value)
    End Operator
    ''' <summary>
    ''' See https://dev59.com/lXVC5IYBdhLWcg3wcgqd
    ''' </summary>
    Public Shared Widening Operator CType(value As ConstantItem) As String
        Return value.Name
    End Operator

End Class

请注意使用 扩展运算符,以省略键入 .Item。如果您不想使用 扩展运算符,则可以将其注释掉,并将 Constants.Types(TypeA) 更改为 Constants.Types.Item(TypeA)
这是您可能需要的描述扩展。
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

这是我使用的导入语句(程序集名为MyPatterns):

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

导入这两个“代码”可以让您在枚举中省略前缀,从而缩短代码。


2

试试这个:

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

至少它将减少在选择语句中编写的代码量。


感谢您的回复。这是一个可行的解决方案,但是@Abraham的提示让我找到了更加优雅的实现方式。 - mburm
1
@mburm,为什么不将您更加优雅的解决方案作为被采纳的答案,并为我们所有人提供启发? - Carl Onager

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接