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

Fer*_*Fer 17 c# design-patterns switch-statement

我以不同的方式找到了一个关于实现枚举的好例子.我认为这就是所谓的类型安全枚举模式.我开始使用它,但我意识到我不能在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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

Ale*_*sev 9

你可以尝试这样的事情:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这有点笨拙,但确实有效.我遇到的唯一问题是带有常量的额外嵌套类,我不喜欢,但必须使用它才能在`switch`语句中提供常量值.还有其他方式吗? (2认同)

Jor*_*dão 7

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

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!
    }
  }

  ...
}
Run Code Online (Sandbox Code Playgroud)

用法:

MyState state = ...
state.someLogic();
Run Code Online (Sandbox Code Playgroud)

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

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) {
    ...
  }
}
Run Code Online (Sandbox Code Playgroud)

然后打开:

switch (state.Value) {
  case MyStateValue.Passed: ...
  case MyStateValue.Failed: ...
}
Run Code Online (Sandbox Code Playgroud)

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