2009-06-01 45 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" 

上面的代碼是一個簡單的靜態實現。如果更改或添加新值,在實際使用中是可取的,或者您希望不必重新編譯 - 那麼設置外部數據資源的值是另一種簡單的選擇。

另一種替代方法是簡單地設置您可以隨意更改的字符串值。簡單的字符串,數組,字典或其他幾十種其他方法 - 這裏的基本概念是在代碼中使用簡單的描述性詞語供程序員參考 - 用戶是(也應該是)完全不知道這種編碼慣例。

所以這真的是程序員的選擇,只受到可重用性,變化頻率,他人理解和數值預期變化水平等因素的限制。