何时以及如何使用枚举类而不是枚举?

时间:2013-05-12 12:25:59

标签: c# design-patterns enumeration separation-of-concerns

最近工作的开发人员开始在枚举通常适合的地方使用类模式而不是枚举。相反,他使用类似于下面的东西:

internal class Suit
{
    public static readonly Suit Hearts = new Suit();
    public static readonly Suit Diamonds = new Suit();
    public static readonly Suit Spades = new Suit();
    public static readonly Suit Clubs = new Suit();
    public static readonly Suit Joker = new Suit();
    private static Suit()
    {

    }
    public static bool IsMatch(Suit lhs, Suit rhs)
    {
        return lhs.Equals(rhs) || (lhs.Equals(Joker) || rhs.Equals(Joker));
    }
}

他的推理是它看起来像一个枚举,但允许他包含与枚举有关的方法(如上面的IsMatch)。

他称这是一个Enumeration类,但这不是我以前见过的。我想知道优点和缺点是什么以及我可以在哪里找到更多信息?

由于

编辑:他描述的另一个优点是能够为枚举添加特定的ToString()实现。

3 个答案:

答案 0 :(得分:4)

Enums在许多场景中都很好,但在其他情况下很差。通常我会发现一些问题 与枚举:

  • 与枚举相关的行为分散在应用程序中
  • 新的枚举值需要霰弹枪手术
  • 枚举不遵循开放原则

由于枚举行为四处散布,我们永远不能将其带回源类型,因为枚举类型不能有任何行为(或者说就是这种状态)。

另一方面,枚举类

每个枚举类型的所有变体不仅可以下推到枚举类,还可以下推到每个特定的子类型。

枚举在各种情况下运行良好,但可以在域模型中快速分解。枚举类提供了大部分相同的可用性,并且具有成为行为目的地的额外好处。

不再需要切换语句,因为我可以将变量和知识推送到模型中。如果由于某种原因我需要检查特定的枚举类值,该选项仍然对我开放。这个模式不应该替换所有枚举,但是有一个替代方案很好。

可以阅读here

答案 1 :(得分:2)

枚举的主要优点是它们基本上是带有一些命名值的整数,因此它们本质上是可移植的和可序列化的。枚举上的算术运算和逻辑运算也更快。

当您需要具有额外状态信息的opaque值时,将使用枚举类。例如,通用数据访问层可以具有如下界面:

public static class Dal
{
    public static Record Query(Operation operation, Parameters parameters);
}

var result = Dal.Query(Operation.DoSomething, new DoSomethingParameters {...});

Dal Operation的用户只是可用操作的枚举,但它可以包含连接字符串,SQL语句或存储过程以及泛型Dal所需的任何其他数据。

另一种“常见”用途是用于系统中的公共模式(状态或策略)。从用户的角度来看,模式是不透明的值,但它可能包含对系统实现至关重要的信息或内部功能。一个人为的例子:


public class TheSystem
{
   public SystemMode Mode;
   public void Save()
   {
      Mode.Save();
   }
   public SystemDocument Read()
   {
      return Mode.Read();
   }
}

public abstract class SystemMode
{
   public static SystemMode ReadOnly = new ReadOnlyMode();
   public static SystemMode ReadWrite = new ReadWriteMode();

   internal abstract void Save();
   internal abstract SystemDocument Read();

   private class ReadOnlyMode : SystemMode
   {
      internal override void Save() {...}
      internal override SystemDocument Read() {...}
   }

   private class ReadWriteMode : SystemMode
   {
      internal override void Save() {...}
      internal override SystemDocument Read() {...}
   }
}


TheSystem.Mode = SystemMode.ReadOnly;

我认为只有IsMatch静态方法不保证不使用简单的枚举。在这种情况下,使用扩展方法可以实现非常相似的东西。

答案 2 :(得分:1)

枚举非常适合轻量级状态信息。例如,您的颜色枚举(不包括蓝色)将有助于查询交通信号灯的状态。真正的颜色以及整个颜色概念及其所有行李(阿尔法,颜色空间等)都无关紧要,只有哪个状态是光线。另外,稍微改变你的枚举以代表交通灯的状态:

[Flags()]
public enum LightColors
{
    unknown = 0,
    red = 1,
    yellow = 2,
    green = 4,
    green_arrow = 8
}

当前灯光状态可以设置为:

LightColors c = LightColors.red | LightColors.green_arrow;

并询问:

if ((c & LightColors.red) == LightColors.red)
    {
        //Don't drive
    }
    else if ((c & LightColors.green_arrow) == LightColors.green_arrow)
    {
        //Turn
    }

静态类颜色成员将能够支持此多状态而无需额外功能。

但是,静态类成员对常用对象很有用。 System.Drawing.Color成员是很好的例子,因为它们代表具有模糊构造函数的已知名称颜色(除非您知道您的十六进制颜色)。如果将它们作为枚举实现,则每次要将该值用作颜色时都必须执行此类操作:

colors c = colors.red;
        switch (c)
        {
            case colors.red:
                return System.Drawing.Color.FromArgb(255, 0, 0);
                break;
            case colors.green:
                return System.Drawing.Color.FromArgb(0,255,0);
                break;
        }

因此,如果你有一个枚举并且发现你经常做一个switch / case / if / else /无论派生一个对象,你可能想要使用静态类成员。如果你只是查询某事的状态,我会坚持使用枚举。此外,如果您必须以不安全的方式传递数据,枚举可能比对象的序列化版本更好。

引用此论坛的旧帖子: When to use enums, and when to replace them with a class with static members?