2009-06-01 43 views
3

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

据我所知,枚举只能映射到数值,而不是字符串。所以我能够想到的最好的是一个静态类,它将常量暴露为内部设置为等于代码值的静态只读字符串字段,如下所示。

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,但后来我不得不做出ReasonCodeEnum非静态类,并给它设置和返回值的方式。

我想知道的是,是否有一种方法可以使用内置的枚举功能来完成我正在做的事情,或者如果没有,是否有这种类型的事物的任何标准设计模式。

+0

我个人认为你应该找到一种方式来驱动数据;就像这样,如果你想出一个新的代码,你必须重新编译。我的鼻子不喜欢它。如果我有一个明确的答案,然后我会把一个下面。 – jcollum 2009-06-01 16:30:52

+0

这取决于 - 如果新代码总是意味着为应用程序的各个部分制定不同的行为,这似乎不太合理。 – 2009-06-01 16:34:49

回答

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... 
0

创建通用词典,其中关键是字符串(或枚举)和值作为代表。 通过键调用字典可以执行绑定到它的动作。

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

1

虽然它并没有解决分配字符串值,以枚举,我认为这可能是解决正如其他人指出,通过简单的字典的问题

Dictionary<string, MyEnum> StringEnumMap; 

你应该看看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); 
0

您可以拥有两个枚举,其中一个具有神秘常量,例如“NA”和具有描述常数的例如“无法使用”。意义相同的事物的常量应映射到相同的整数。在枚举和整数之间转换很容易,所以剩下的问题是如何在枚举和字符串之间轻松转换。

方法如下:

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

没有保证,这将工作速度快,但它会饶你从一个大的switch语句。

1

作为一个学习项目原来的问题和群体的反应都非常优秀。除了过度复杂化问题的具体原因之外,为什么不使用常量?

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

上面的代码是一个简单的静态实现。如果更改或添加新值,在实际使用中是可取的,或者您希望不必重新编译 - 那么设置外部数据资源的值是另一种简单的选择。

另一种替代方法是简单地设置您可以随意更改的字符串值。简单的字符串,数组,字典或其他几十种其他方法 - 这里的基本概念是在代码中使用简单的描述性词语供程序员参考 - 用户是(也应该是)完全不知道这种编码惯例。

所以这真的是程序员的选择,只受到可重用性,变化频率,他人理解和数值预期变化水平等因素的限制。