如何在类型安全的枚举模式上使用switch语句

我以不同的方式找到了一个关于实现枚举的好例子。 我认为这就是所谓的类型安全枚举模式 。 我开始使用它,但我意识到我不能在switch语句中使用它。
我的实现如下所示:

public sealed class MyState { private readonly string m_Name; private readonly int m_Value; public static readonly MyState PASSED= new MyState(1, "OK"); public static readonly MyState FAILED= new MyState(2, "ERROR"); private MyState(int value, string name) { m_Name = name; m_Value = value; } public override string ToString() { return m_Name; } public int GetIntValue() { return m_Value; } } 

为了能够在C#中的switch语句中使用这种模式,我可以添加到我的类中?
谢谢。

你可以尝试这样的事情:

 class Program { static void Main(string[] args) { Gender gender = Gender.Unknown; switch (gender) { case Gender.Enum.Male: break; case Gender.Enum.Female: break; case Gender.Enum.Unknown: break; } } } public class Gender : NameValue { private Gender(int value, string name) : base(value, name) { } public static readonly Gender Unknown = new Gender(Enum.Unknown, "Unknown"); public static readonly Gender Male = new Gender(Enum.Male, "Male"); public static readonly Gender Female = new Gender(Enum.Female, "Female"); public class Enum { public const int Unknown = -1; public const int Male = 1; public const int Female = 2; } } public abstract class NameValue { private readonly int _value; private readonly string _name; protected NameValue(int value, string name) { _value = value; _name = name; } public int Value { get { return _value; } } public string Name { get { return _name; } } public override string ToString() { return Name; } public override int GetHashCode() { return Value.GetHashCode(); } public override bool Equals(object obj) { NameValue other = obj as NameValue; if (ReferenceEquals(other, null)) return false; return this.Value == other.Value; } public static implicit operator int(NameValue nameValue) { return nameValue.Value; } } 

类型安全的枚举模式很有趣,因为您可以向单个枚举成员(实例)添加行为 。 因此,如果您要切换的行为可能是该类的一部分,那么只需使用多态。 请注意,您可能需要为覆盖该行为的每个成员创建子类:

 public class MyState { public static readonly MyState Passed = new MyStatePassed(); public static readonly MyState Failed = new MyStateFailed(); public virtual void SomeLogic() { // default logic, or make it abstract } class MyStatePassed : MyState { public MyStatePassed() : base(1, "OK") { } } class MyStateFailed : MyState { public MyStateFailed() : base(2, "Error") { } public override void SomeLogic() { // Error specific logic! } } ... } 

用法:

 MyState state = ... state.someLogic(); 

现在,如果逻辑显然不属于您并且您真的想切换,我的建议是创建一个兄弟枚举:

 public enum MyStateValue { Passed = 1, Failed = 2 } public sealed class MyState { public static readonly MyState Passed = new MyState(MyStateValue.Passed, "OK"); public static readonly MyState Failed = new MyState(MyStateValue.Failed, "Error"); public MyStateValue Value { get; private set; } private MyState(MyStateValue value, string name) { ... } } 

并打开:

 switch (state.Value) { case MyStateValue.Passed: ... case MyStateValue.Failed: ... } 

在这种情况下,如果类型安全的枚举类没有任何行为,那么它没有太多理由代替枚举本身存在。 但是,当然,你可以同时拥有逻辑和兄弟节目。

Jordão有正确的想法,但有一种更好的方法来实现多态,使用委托

委托的使用比switch语句快。 (事实上​​,我坚信,面向对象开发中switch语句的唯一位置是工厂方法。我总是寻找某种多态来替换我处理的任何代码中的任何switch语句。)

例如,如果您想要基于type-safe-enum的特定行为,则使用以下模式:

 public sealed class EnumExample { #region Delegate definitions ///  /// This is an example of adding a method to the enum. /// This delegate provides the signature of the method. ///  /// A parameter for the delegate /// Specifies the return value, in this case a (possibly /// different) EnumExample private delegate EnumExample DoAction(string input); #endregion #region Enum instances ///  /// Description of the element /// The static readonly makes sure that there is only one immutable /// instance of each. ///  public static readonly EnumExample FIRST = new EnumExample(1, "Name of first value", delegate(string input) { // do something with input to figure out what state comes next return result; } ); ... #endregion #region Private members ///  /// The string name of the enum ///  private readonly string name; ///  /// The integer ID of the enum ///  private readonly int value; ///  /// The method that is used to execute Act for this instance ///  private readonly DoAction action; #endregion #region Constructors ///  /// This constructor uses the default value for the action method /// /// Note all constructors are private to prevent creation of instances /// by any other code ///  /// integer id for the enum /// string value for the enum private EnumExample(int value, string name) : this (value, name, defaultAction) { } ///  /// This constructor sets all the values for a single instance. /// All constructors should end up calling this one. ///  /// the integer ID for the enum /// the string value of the enum /// the method used to Act private EnumExample(int value, string name, DoAction action) { this.name = name; this.value = value; this.action = action; } #endregion #region Default actions ///  /// This is the default action for the DoAction delegate ///  /// The inpute for the action /// The next Enum after the action static private EnumExample defaultAction(string input) { return FIRST; } #endregion ... }