Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何在类型安全枚举模式上使用switch语句_C#_Design Patterns_Switch Statement - Fatal编程技术网

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

C# 如何在类型安全枚举模式上使用switch语句,c#,design-patterns,switch-statement,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"); pub

我发现了一个以不同方式实现枚举的好看示例。我想这就是所谓的类型安全枚举模式。我开始使用它,但我意识到我不能在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语句中使用此模式,我可以向类添加哪些内容?

谢谢。

类型安全枚举模式很有趣,因为您可以向单个枚举成员(即实例)添加行为。因此,如果您想要打开的行为可能是类的一部分,只需使用多态性。请注意,您可能需要为每个重写行为的成员创建子类:

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: ...
}

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

您可以尝试以下方法:

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

Jordão的想法是正确的,但是有更好的方法来实现多态性,使用delegate

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

例如,如果需要基于类型安全枚举的特定行为,我将使用以下模式:

public sealed class EnumExample
{
    #region Delegate definitions
    /// <summary>
    /// This is an example of adding a method to the enum. 
    /// This delegate provides the signature of the method.
    /// </summary>
    /// <param name="input">A parameter for the delegate</param>
    /// <returns>Specifies the return value, in this case a (possibly 
    /// different) EnumExample</returns>
    private delegate EnumExample DoAction(string input);
    #endregion

    #region Enum instances
    /// <summary>
    /// Description of the element
    /// The static readonly makes sure that there is only one immutable 
    /// instance of each.
    /// </summary>
    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
    /// <summary>
    /// The string name of the enum
    /// </summary>
    private readonly string name;
    /// <summary>
    /// The integer ID of the enum
    /// </summary>
    private readonly int value;
    /// <summary>
    /// The method that is used to execute Act for this instance
    /// </summary>
    private readonly DoAction action;
    #endregion

    #region Constructors
    /// <summary>
    /// This constructor uses the default value for the action method
    /// 
    /// Note all constructors are private to prevent creation of instances 
    /// by any other code
    /// </summary>
    /// <param name="value">integer id for the enum</param>
    /// <param name="name">string value for the enum</param>
    private EnumExample(int value, string name) 
            : this (value, name, defaultAction)
    {
    }

    /// <summary>
    /// This constructor sets all the values for a single instance.
    /// All constructors should end up calling this one.
    /// </summary>
    /// <param name="value">the integer ID for the enum</param>
    /// <param name="name">the string value of the enum</param>
    /// <param name="action">the method used to Act</param>
    private EnumExample(int value, string name, DoAction action)
    {
        this.name = name;
        this.value = value;
        this.action = action;
    }
    #endregion

    #region Default actions
    /// <summary>
    /// This is the default action for the DoAction delegate
    /// </summary>
    /// <param name="input">The inpute for the action</param>
    /// <returns>The next Enum after the action</returns>
    static private EnumExample defaultAction(string input)
    {
        return FIRST;
    }
    #endregion

    ...
}
公共密封类枚举示例
{
#区域代理定义
/// 
///这是向枚举添加方法的示例。
///此委托提供方法的签名。
/// 
///委托的参数
///指定返回值,在本例中为a(可能是
///不同的)枚举示例
私有委托枚举示例DoAction(字符串输入);
#端区
#区域枚举实例
/// 
///元素的描述
///静态readonly确保只有一个不可变
///每个实例。
/// 
public static readonly EnumExample FIRST=新的EnumExample(1,
“第一个值的名称”,
委托(字符串输入)
{
//对输入进行一些处理,以确定下一个状态
返回结果;
}
);
...
#端区
#区域私人成员
/// 
///枚举的字符串名称
/// 
私有只读字符串名称;
/// 
///枚举的整数ID
/// 
私有只读int值;
/// 
///用于为此实例执行Act的方法
/// 
私有只读操作;
#端区
#区域构造函数
/// 
///此构造函数使用action方法的默认值
/// 
///注意:所有构造函数都是私有的,以防止创建实例
///按任何其他代码
/// 
///枚举的整数id
///枚举的字符串值
私有枚举示例(int值、字符串名称)
:此(值、名称、默认操作)
{
}
/// 
///此构造函数为单个实例设置所有值。
///所有构造函数都应该调用这个函数。
/// 
///枚举的整数ID
///枚举的字符串值
///采取行动的方法
私有枚举示例(int值、字符串名称、DoAction操作)
{
this.name=名称;
这个值=值;
这个动作=动作;
}
#端区
#区域默认操作
/// 
///这是DoAction委托的默认操作
/// 
///行动的委托人
///操作后的下一个枚举
静态私有枚举示例defaultAction(字符串输入)
{
先返回;
}
#端区
...
}

关于标准枚举实现,什么是不够“类型安全”的?GetIntValue应该是一个名为
Value
ID
的属性。您可以使用@CodyGray切换该属性树,枚举的全部要点是类型安全性。@CodyGray请参阅以下问题:。我从这个问题的答案中得到了实现。我认为这就像Enum的标准设计模式。好吧,我想我必须想另一种方法来实现我的目标。谢谢。@Fer您的类用法而不是枚举是绝对正确的。由于许多原因,我从不在C#中使用枚举。非常感谢您的关注。我尝试了你的第二个选择,它奏效了(创建兄弟枚举)。现在,@AlexBurtsev的答案似乎更适合我的研究。但我也会保留你的解决方案。非常感谢。这确实有帮助。这有点笨拙,但确实有效。我唯一的问题是我不喜欢的带有常量的附加嵌套类,但是为了在
switch
语句情况下提供常量值,必须使用它。也许还有别的办法?