C# 中的智能枚举
具有附加功能的标准枚举的替代方案。
引言
很久以前,我从 John Skeet 的博客上了解到 Java 枚举是功能完善的类。这种方法具有明显的优势:您可以为枚举添加行为。
我在 Stackoverflow 上找到了如何在 C# 中实现它的解决方案。不幸的是,它们都无法与 switch 语句一起工作,因为 case 之后需要跟一个常量值,而该值不能是引用类型(字符串是编译器提供特殊支持的唯一例外)。
随着 C# 7.0 的发布,情况发生了变化,新的增强型 switch 语句也随之而来。
使用代码
基本思想是将枚举更改为不可变类,并公开该类的静态只读实例。
我将大部分样板代码放在 EnumBase
类中。这包括序列化支持、比较运算符等。我的所有枚举都继承自这个类。
在 EnumBase
类中,我假设枚举值在内部由 int 表示。该类还支持枚举描述,在标准的枚举中,通常由一些自定义属性表示。
例如,这里是 TransactionState
类
public class TransactionState : EnumBase { public static readonly TransactionState COMPLETE = new TransactionState(1, "Transaction complete"); public static readonly TransactionState REJECTED = new TransactionState(2, "Transaction rejected"); public static readonly TransactionState PENDING = new TransactionState(3, "Transaction pending"); public static readonly TransactionState AWAITING_APPROVAL = new TransactionState(4, "Transaction awaiting approval"); private TransactionState(int value, string description) : base(value, description) { } private TransactionState(SerializationInfo info, StreamingContext context) : base(info, context) { } public virtual bool IsTransactionComplete() { if (value == 1) return true; return false; } }
这个例子基于这个博客中的 Java 示例:http://blog.scottlogic.com/2016/07/28/java-enums-how-to-use-them-smarter.html
正如你所见,只有很少的样板代码——一个额外的构造函数用于正确的序列化,另一个用于初始化值。
IsTransactionComplete
是一个在枚举本身内部添加一些有用逻辑的方法:它决定了枚举的类别。使用标准的枚举,您需要在其他辅助类中实现此功能。
现在是时候展示这个类的用法了
class Program
{
static void Main()
{
TransactionState value = TransactionState.PENDING;
TransactionState secondValue = TransactionState.COMPLETE;
// Use switch with pattern matching.
switch (value)
{
case var tsValue when tsValue == TransactionState.COMPLETE && secondValue == TransactionState.AWAITING_APPROVAL:
Console.WriteLine("Y");
break;
case var tsValue when tsValue == TransactionState.PENDING && secondValue == TransactionState.COMPLETE:
Console.WriteLine("Value is PENDING, secondValue is COMPLETE");
break;
case var tsValue when tsValue == TransactionState.REJECTED:
Console.WriteLine("Z");
break;
}
if (value.IsTransactionComplete())
{
Console.WriteLine("Value is COMPLETE");
}
else
{
Console.WriteLine("Value is not COMPLETE");
}
Console.WriteLine("value.Tostring(): {0}", value.ToString());
}
}
我使用了带有模式匹配和 when 关键字的新 switch 形式。
结论
从 C# 7.0 开始,您可以在枚举的位置使用标准类,这在更复杂的情况下可以提供更大的灵活性和可用性。