.NET字符串值的符号常量枚举

时间:2009-06-01 16:17:14

标签: .net vb.net enums constants

我有一个相当无意义的代码列表,我正在使用VB.NET Windows应用程序处理。对于我正在编写处理这些代码的业务逻辑,我想使用有意义的常量(如ServiceNotCoveredMemberNotEligible)而不是原始代码(如"SNCV"和{{ 1}})。

据我所知,Enums只能映射到数值,而不能映射到字符串。因此,我能够提出的最好的是一个静态类,它将常量公开为静态只读字符串字段,这些字段在内部设置为等于代码值,如下所示。

"MNEL"

在上面的示例中,如果我可以将Public Class MyClass private _reasonCode as String() Public Property ReasonCode() As String 'Getter and Setter... End Property Public Class ReasonCodeEnum Private Sub New() End Sub Public Shared ReadOnly ServiceNotCovered As String = "SNCV" Public Shared ReadOnly MemberNotEligible As String = "MNEL" 'And so forth... End Class End Class 'Calling method Public Sub ProcessInput() Dim obj As New MyClass() Select Case obj.ReasonCode Case MyClass.ReasonCodeEnum.ServiceNotCovered 'Do one thing Case MyClass.ReasonCodeEnum.MemberNotEligible 'Do something different 'Other enum value cases and default End Select End Sub 定义为类型MyClass.ReasonCode,那会很好,但是我必须让ReasonCodeEnum成为非静态类并给它一个设置和返回值的方法。

我想知道是否有办法使用内置的Enum功能来做我正在做的事情,或者如果没有,是否有任何标准设计模式适用于此类事情。

7 个答案:

答案 0 :(得分:7)

您可以将字符串放在字典中并找到等效的enum值,而不是大Select Case语句:

Public Enum ReasonCode
    ServiceNotCovered
    MemberNotEligible
End Enum


Private mapping As New Dictionary(Of String, ReasonCode)
' Add the required mappings and look up the dictionary...

答案 1 :(得分:2)

两个选项表明自己:

1)使用枚举并为每个值添加Description属性。然后,您可以相当轻松地构建从值到描述的地图。

优点:

  • 仍为值类型
  • 可以在switch语句中使用

缺点:

  • 不是真的OO

2)不要使用.NET枚举 - 使用更像Java枚举的东西。这基本上涉及使用私有构造函数编写公共不可变类,并提供公共(只读)共享属性/字段。这里有一些C#来展示我的意思 - 希望你在阅读C#时比我在编写VB时更好:)

public sealed class Reason
{
    public static readonly Reason ServiceNotCovered = new Reason("SNCV");
    public static readonly Reason MemberNotEligible = new Reason("MNEL");

    private readonly string code;

    private Reason(string code)
    {
        this.code = code;
    }

    public string Code
    {
        get { return code; }
    }
}

现在,你不能不开启这个(至少不是在C#中 - 我不知道VB的Select是否更灵活)但是无论你切换它,值得思考你是否可以在枚举本身内提供相同的功能。这是一个很好的OO思考方式。不同的原因可以通过多态性提供不同的功能。例如:

public class Reason
{
    public static readonly Reason ServiceNotCovered = new ServiceReason();
    public static readonly Reason MemberNotEligible = new EligibilityReason();

    private readonly string code;

    private Reason(string code)
    {
        this.code = code;
    }

    public string Code
    {
        get { return code; }
    }

    public abstract void DoSomething();

    private class ServiceReason : Reason
    {
        internal ServiceReason() : base("SVNC") {}

        public override void DoSomething()
        {
            // Whatever
        }
    }

    private class EligibiltyReason : Reason
    {
        internal EligibiltyReason() : base("MNEL") {}

        public override void DoSomething()
        {
            // Do something else
        }
    }
}

然后,您可以通过创建与组相同的派生类型来“分组”具有相似行为的不同原因 - 并且调用者不必知道任何有关它们的信息。

这就是假设VB的访问控制在嵌套类型方面与C#的工作方式相同,能够访问其外部类的私有成员(特别是构造函数)。

就代码而言,这是一个相当冗长的解决方案,但它确实有助于在类型本身中保持关于“枚举”权利的所有决策。然而,就其作为参考类型而言还有另一个缺点 - 因此您需要以正常方式检查无效性。另一方面,枚举也没有提供任何真正的防御错误 - 如果你想检查一个参数,你必须使用Enum.IsDefined

答案 2 :(得分:1)

虽然它没有解决将字符串值分配给枚举的问题,我认为可能会解决这个问题,正如其他人通过简单的词典所指出的那样

Dictionary<string, MyEnum> StringEnumMap;

您应该查看Google代码中的Stateless project(我的首选代码)或codeplex上的Simple State Machine来封装逻辑。它的冗长程度令人惊叹,我认为它可以完全满足您的需求。无状态项目主页的一个例子:

var phoneCall = new StateMachine<State, Trigger>(State.OffHook);

phoneCall.Configure(State.OffHook)
    .Allow(Trigger.CallDialed, State.Ringing);

phoneCall.Configure(State.Ringing)
    .Allow(Trigger.HungUp, State.OffHook)
    .Allow(Trigger.CallConnected, State.Connected);

phoneCall.Configure(State.Connected)
    .OnEntry(t => StartCallTimer())
    .OnExit(t => StopCallTimer())
    .Allow(Trigger.LeftMessage, State.OffHook)
    .Allow(Trigger.HungUp, State.OffHook)
    .Allow(Trigger.PlacedOnHold, State.OnHold);

phoneCall.Configure(State.OnHold)
    .SubstateOf(State.Connected)
    .Allow(Trigger.TakenOffHold, State.Connected)
    .Allow(Trigger.HungUp, State.OffHook)
    .Allow(Trigger.PhoneHurledAgainstWall, State.PhoneDestroyed);

答案 3 :(得分:1)

您可以使用我在此处发布的代码模拟VB.Net中任何类型的自定义枚举:
Getting static field values of a type using reflection

答案 4 :(得分:1)

作为学习项目原始问题和小组的反应非常好。除了有特定原因使问题过于复杂之外,为什么不使用常量?

Const ServiceNotCovered As String = "SNCV"
Const MemberNotEligible As String = "MNEL"

上面的代码是一个简单的静态实现。如果需要更改或添加新值,在实际使用中,和/或您希望不必重新编译 - 那么从外部数据资源设置值是另一种简单的替代方法。

另一种方法是简单地设置您可以随意更改的字符串值。无论是简单的字符串,数组,字典还是其他几十种方法 - 这里的基本概念是使用简单的描述性单词在程序员中引用 - 用户(并且应该)完全不知道这种编码约定。

所以这实际上是程序员的选择,并且只受到可重用性,变化频率,他人理解以及价值预期变化程度等因素的限制。

答案 5 :(得分:0)

创建通用字典,其中键是字符串(或枚举),值是委托。 按键调用字典可以执行绑定到它的操作。

答案 6 :(得分:0)

你可以有两个枚举,一个含有神秘的常数,例如: “NA”,以及具有描述性常数的一个,例如“无法使用”。意味着相同的常量应该映射到相同的整数。在枚举和整数之间转换很容易,因此剩下的问题是如何在枚举和字符串之间轻松转换。

以下是:

using System.ComponentModel;
...
EnumConverter conv = new EnumConverter( typeof( MyEnum ) );
...
conv.ConvertToString( ... );
conv.ConvertFromString( ... );

不能保证这会很快发挥作用,但它会让你免于大的转换声明。