何时以及如何使用枚举类而不是枚举
本文关键字:枚举 何使用 何时 | 更新日期: 2023-09-27 18:13:16
工作中的一个开发人员最近开始在通常适合枚举的地方使用类模式而不是枚举。相反,他使用了类似于下面的内容:
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()实现。
枚举在许多情况下都很好,但在其他情况下却很差。通常我会发现一些问题with Enums:
- 与枚举相关的行为分散在应用程序中
- 新的枚举值需要霰弹枪手术
- 枚举不遵循开闭原则
由于枚举行为分散在各处,我们永远不能将其带回到源类型,因为枚举类型不能有任何行为(或状态)。
另一方面,使用枚举类:每个枚举类型的所有变体不仅可以下推到枚举类,而且可以下推到每个特定的子类型。
枚举在各种情况下都能很好地工作,但是在您的域模型中可能会很快崩溃。枚举类提供了许多相同的可用性,其附加的好处是成为行为的目标。
Switch语句不再是必要的,因为我可以将可变性和知识推到它所属的位置,回到模型中。如果出于某种原因我需要检查特定的枚举类值,则仍然可以使用该选项。这个模式不应该取代所有的枚举,但是有一个替代方法是很好的。
可以在这里读
枚举的主要优点是它们基本上是带有一些命名值的整数,因此它们本质上是可移植和可序列化的。算术和逻辑运算在枚举上也更快。
枚举类在需要具有额外状态信息的不透明值时使用。例如,一个通用的数据访问层可以有这样的接口:
<>之前公共静态类Dal{公共静态记录查询(操作操作,参数参数);}var result = Dal.Query(操作。DoSomethingParameters{…});之前对于Dal操作的用户来说,只是一个可用操作的枚举,但它可以包含连接字符串、SQL语句或存储过程以及通用Dal所需的任何其他数据。
另一个"常见"用途是系统中的公共模式(状态或策略)。从用户的角度来看,mode是一个不透明的值,但它可能包含对系统实现至关重要的信息或内部功能。一个做作的例子:
<>之前公共类系统{public SystemMode模式;public void Save(){Mode.Save ();}public SystemDocument Read(){返回Mode.Read ();}}抽象类SystemMode{public static SystemMode ReadOnly = new ReadOnlyMode();public static SystemMode ReadWrite = new ReadWriteMode();内部抽象void Save();内部抽象SystemDocument Read();ReadOnlyMode: SystemMode{内部覆盖无效保存(){…}内部重写SystemDocument Read(){…}}private类ReadWriteMode: SystemMode{内部覆盖无效保存(){…}内部重写SystemDocument Read(){…}}}该系统。Mode = SystemMode.ReadOnly;之前我不认为仅仅有一个IsMatch静态方法就可以保证不使用简单的枚举。在本例中,可以使用扩展方法实现非常相似的功能。
枚举非常适合轻量级状态信息。例如,您的颜色枚举(不包括蓝色)将用于查询交通灯的状态。真正的颜色以及颜色的整个概念和所有的包袱(alpha,色彩空间等)都不重要,重要的是光处于哪个状态。另外,稍微改变enum以表示交通灯的状态:
[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/任何派生对象,你可能想要使用静态类成员。如果你只是查询某物的状态,我会坚持使用枚举。此外,如果必须以不安全的方式传递数据,枚举可能比对象的序列化版本保存得更好。
参考来自这个论坛的旧帖子:何时使用枚举,何时用带有静态成员的类替换它们?