相关文章推荐
大力的跑步机  ·  丧偶皇后情头,丧偶皇后漫剧漫画视频 - 快看漫画·  2 年前    · 
谦和的冰棍  ·  从雷克萨斯RZ身上,我看不到雷克萨斯未来|丰 ...·  2 年前    · 
发财的包子  ·  从“守望者”到“老赖”:朱新礼又爆新危机 ...·  2 年前    · 
爱笑的小蝌蚪  ·  【奥迪A6 e-tron】_新款奥迪A6 ...·  2 年前    · 
眼睛小的蚂蚁  ·  一口气看完《我有无敌剑域》合集!#一口气看完 ...·  2 年前    · 
Code  ›  C#的“智能枚举”:在枚举中增加行为?开发者社区
信用卡 智能社区 enum 枚举类型
https://cloud.tencent.com/developer/article/2319556
考研的丝瓜
11 月前
郑子铭

C#的“智能枚举”:在枚举中增加行为?

前往小程序,Get 更优 阅读体验!
立即前往
腾讯云
开发者社区
文档 建议反馈 控制台
首页
学习
活动
专区
工具
TVP
最新优惠活动
文章/答案/技术大牛
发布
首页
学习
活动
专区
工具
TVP 最新优惠活动
返回腾讯云官网
郑子铭
首页
学习
活动
专区
工具
TVP 最新优惠活动
返回腾讯云官网
社区首页 > 专栏 > C#的“智能枚举”:在枚举中增加行为?

C#的“智能枚举”:在枚举中增加行为?

作者头像
郑子铭
发布 于 2023-08-30 10:59:02
发布 于 2023-08-30 10:59:02
390 0
举报
文章被收录于专栏: DotNet NB && CloudNative

枚举的基本用法回顾

以下是一个常见的 C# 枚举( enum )的示例:

代码语言: javascript
复制
enum Weekday
    Monday,
    Tuesday,
    Wednesday,
    Thursday,
    Friday,
    Saturday,
    Sunday
}
代码语言: javascript
复制
class Program
    static void Main(string[] args)
        Weekday today = Weekday.Tuesday;
        Console.WriteLine("今天是" + today.ToString() + "。");
        Console.WriteLine("明天是" + (Weekday)(((int)today + 1) % 7) + "。");
        Console.WriteLine("昨天是" + (Weekday)(((int)today + 6) % 7) + "。");

在这个示例中,我们定义了一个名为 Weekday 的枚举,其中包括每个星期的日子。然后在 Main 方法中,我们将 today 变量设置为 Tuesday ,并使用 ToString() 方法将其转换为字符串。

接下来,我们计算并输出明天和昨天的日子。我们使用强制类型转换将枚举值转换为整数,然后在取模 7 意义下加或减 1 或 6,以便正确地计算出前一天或后一天的日子。

输出结果应该是这样的:

代码语言: javascript
复制
今天是 Tuesday。
明天是 Wednesday。
昨天是 Monday。

枚举常见的设计模式运用

enum 可以应用在许多种设计模式下:

  • 状态模式
  • 策略模式
  • 工厂模式
  • 观察者模式

介绍

  1. 状态模式

状态模式用于根据对象的内部状态来改变其行为。 enum 可以很好地表示对象的状态,因此它是实现状态模式的常见选择。在 C# 中,您可以使用 switch 语句来根据不同的 enum 值执行不同的操作。

  1. 策略模式

策略模式允许您根据运行时条件选择不同的算法或行为。 enum 可以很好地表示这些条件,因此它是实现策略模式的常见选择。在 C# 中,您可以使用 switch 语句或 if-else 语句来根据不同的 enum 值选择不同的算法或行为。

  1. 工厂模式

工厂模式允许您使用一个共同的接口来创建不同的对象。 enum 可以很好地表示这些对象的类型,因此它是实现工厂模式的常见选择。在 C# 中,您可以使用 switch 语句或 if-else 语句来根据不同的 enum 值创建不同的对象。

  1. 观察者模式

观察者模式用于建立对象之间的松散耦合关系。 enum 可以很好地表示观察者对象的状态,因此它是实现观察者模式的常见选择。在 C# 中,您可以使用 enum 来表示观察者对象的状态,并使用委托或事件来通知观察者对象。

智能枚举

什么是智能枚举? 智能枚举 不是官方的一个称谓,而是作者定义的一个名词。

这种带行为的一种枚举,简单的可以定义为: 智能枚举 = 枚举 + 丰富的行为 。

它由原来的 enum 类型(值类型)改变成了 class 类型(引用类型),允许您将行为和方法绑定到每个枚举类型上。这意味着您可以在枚举类型上调用方法和属性,就像在类实例上调用它们一样。

智能枚举跟设计模式的意义一样,可以帮助您避免重复的代码,并提高代码的可读性和可维护性。它们还可以使您的代码更加类型安全,因为编译器可以验证您是否使用了正确的枚举值。

代码示例

首先,我们先定义一个抽象的类型,方便后续重用:

代码语言: javascript
复制

public abstract class Enumeration<TEnum> : IEquatable<Enumeration<TEnum>> where TEnum : Enumeration<TEnum>
    private static readonly Dictionary<int, TEnum?> Enumerations = GetEnumerations();
    /// <summary>
    /// 枚举类型
    /// </summary>
    private static readonly Type EnumType = typeof(TEnum);
    protected Enumeration(int value, string name)
        Value = value;
        Name = name;
    /// <summary>
    /// 名称
    /// </summary>
    public string Name { get; protected init; }
    /// <summary>
    /// 值
    /// </summary>
    public int Value { get; protected init; }
    public static TEnum? FromName(string name) => Enumerations.Values.SingleOrDefault(x => x.Name == name);
    public static TEnum? FromValue(int value) => Enumerations.TryGetValue(value, out var enumeration) ? enumeration : default;
    public bool Equals(Enumeration<TEnum>? other) => other is not null && GetType() == other.GetType() && Value == other.Value;
    public override bool Equals(object? obj) => obj is Enumeration<TEnum> other && Equals(other);
    public override int GetHashCode() => HashCode.Combine(Value, Name);
    private static Dictionary<int, TEnum?> GetEnumerations() => EnumType
        .GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy)
        .Where(x => EnumType.IsAssignableFrom(x.FieldType))
        .Select(x => (TEnum?)x.GetValue(default)).ToDictionary(x => x?.Value ?? 0);

先简单解读一下。

这是一个通用的 C# 抽象类,用于实现枚举的高级功能。它使用泛型类型 TEnum 来表示枚举类型,并继承自 IEquatable<Enumeration<TEnum>> 接口,以支持比较操作。

这个抽象类包含了一些常用的枚举操作方法,例如 FromName 和 FromValue ,它们可以通过名称或值来获取枚举值。它还重写了 Equals 和 GetHashCode 方法,以便可以比较两个枚举值是否相等。

该类中的核心方法是 GetEnumerations ,它使用反射获取当前枚举类型中的所有字段,并将它们转换为枚举值。在这个过程中,它还会检查字段的类型是否与枚举类型相同,并将值存储在一个字典中,以便以后可以快速地访问它们。

通过继承这个抽象类,您可以轻松地实现自己的枚举类型,并获得许多有用的功能,例如通过名称和值获取枚举值,并支持比较操作。

业务应用

我们通常会将枚举类型这样定义,而在触发业务逻辑时会使用 switch 来执行不同的行为,这样就很容易会将逻辑分散在不同的地方。

代码语言: javascript
复制

/// <summary>
/// 信用卡类型
/// </summary>
public enum CreditCardType
    None = 0,
    Standard = 1,
    Silver = 2,
    Gold = 3,

那么升级后的智能枚举应该是怎样的呢?它到底智能在哪里?

代码语言: javascript
复制

/// <summary>
/// 信用卡
/// </summary>
public abstract class CreditCard : Enumeration<CreditCard>
    public static readonly CreditCard Gold = new GoldCreditCard();
    public static readonly CreditCard Silver = new SilverCreditCard();
    public static readonly CreditCard Standard = new StandardCreditCard();
    public static readonly CreditCard None = new NoneCreditCard();
    private CreditCard(int value, string name) : base(value, name)
    /// <summary>
    /// 折扣
    /// </summary>
    public abstract double Discount { get; }
    /// <summary>
    /// 金卡
    /// </summary>
    private sealed class GoldCreditCard : CreditCard
        public GoldCreditCard() : base(3, nameof(Gold))
        public override double Discount => 0.2;
    private sealed class SilverCreditCard : CreditCard
        public SilverCreditCard() : base(2, nameof(Silver))
        public override double Discount => 0.1;
    /// <summary>
    /// 标准
    /// </summary>
    private sealed class StandardCreditCard : CreditCard
        public StandardCreditCard() : base(1, nameof(Standard))
        public override double Discount => 0.05;
    /// <summary>
    /// 无
    /// </summary>
    private sealed class NoneCreditCard : CreditCard
        public NoneCreditCard() : base(0, nameof(None))
        public override double Discount => 0;

这里简单解读一下。

这是一个信用卡枚举类型的实现,它继承了之前提到的通用枚举类 Enumeration 。其中, GoldCreditCard 、 SilverCreditCard 、 StandardCreditCard 和 NoneCreditCard 是四个具体的信用卡子类。

每个子类都重写了父类 CreditCard 中的 Discount 属性,以表示不同信用卡的折扣率。 GoldCreditCard 有最高的折扣率, NoneCreditCard 没有任何折扣。

在 CreditCard 类中, Gold 、 Silver 、 Standard 和 None 是四个静态实例,表示四种不同的信用卡类型。每个实例都是通过相应的子类创建的,并传入相应的值和名称。值用于标识枚举类型的唯一性,而名称则是该类型的字符串表示。

通过这种方式,我们可以轻松地定义和使用不同类型的信用卡。例如,可以通过 CreditCard.Gold 来引用 Gold 信用卡的实例,并获取它的折扣率。在需要使用信用卡类型的地方,也可以直接使用 CreditCard 类型来表示。

我们平时也可以这样使用,通过 FromName 和 FromValue :

代码语言: javascript
复制

public class SmartEnumsTests
    private readonly ITestOutputHelper _testOutputHelper;
    public SmartEnumsTests(ITestOutputHelper testOutputHelper)
        _testOutputHelper = testOutputHelper;
    /// <summary>
    /// 基本用法
    /// </summary>
    [Fact]
    public void Use()
        var standardCard = CreditCard.FromName("Standard");
 
推荐文章
大力的跑步机  ·  丧偶皇后情头,丧偶皇后漫剧漫画视频 - 快看漫画
2 年前
谦和的冰棍  ·  从雷克萨斯RZ身上,我看不到雷克萨斯未来|丰田|比亚迪|电动车|中型suv_网易订阅
2 年前
发财的包子  ·  从“守望者”到“老赖”:朱新礼又爆新危机 ,汇源果汁“帝国”风雨飘摇 - 21财经
2 年前
爱笑的小蝌蚪  ·  【奥迪A6 e-tron】_新款奥迪A6 e-tron_奥迪(进口)奥迪A6 e-tron报价及图片_配置–新浪汽车
2 年前
眼睛小的蚂蚁  ·  一口气看完《我有无敌剑域》合集!#一口气看完系列 #漫画解说 #漫画推荐 #二次元_哔哩哔哩_bilibili
2 年前
今天看啥   ·   Py中国   ·   codingpro   ·   小百科   ·   link之家   ·   卧龙AI搜索
删除内容请联系邮箱 2879853325@qq.com
Code - 代码工具平台
© 2024 ~ 沪ICP备11025650号