65.9K
CodeProject 正在变化。 阅读更多。
Home

C# 中的智能枚举

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.43/5 (20投票s)

2017年7月31日

CPOL

1分钟阅读

viewsIcon

25936

downloadIcon

216

具有附加功能的标准枚举的替代方案。

引言

很久以前,我从 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 开始,您可以在枚举的位置使用标准类,这在更复杂的情况下可以提供更大的灵活性和可用性。

© . All rights reserved.