使用枚举类来代替枚举类型
Enumerations (or enum types for short) are a thin language wrapper around an integral type. You might want to limit their use to when you are storing one value from a closed set of values. Classification based on sizes (small, medium, large) is a good example. Using enums for control flow or more robust abstractions can be a code smell. This type of usage leads to fragile code with many control flow statements checking values of the enum.
枚举(或简称为枚举类型)本质上只是基于整型类型的一层薄薄的语言包装。你可能需要将它们的使用场景限制在:仅用于存储一个封闭值集合中的某一个值。比如基于尺寸的分类(小、中、大)就是一个很好的例子。如果把枚举用于控制流或者更健壮的抽象,可能会成为一种“代码坏味道”。这种用法会导致代码变得非常脆弱,因为会出现大量针对枚举值进行检查的控制流语句。
Instead, you can create Enumeration classes that enable all the rich features of an object-oriented language.
取而代之的是,你可以创建“枚举类”,这样就能充分利用面向对象编程语言的所有丰富特性。
However, this isn't a critical topic and in many cases, for simplicity, you can still use regular enum types if that's your preference. The use of enumeration classes is more related to business-related concepts.
不过,这并不是一个绝对的关键话题。在很多情况下,如果你觉得方便,依然可以使用常规的枚举类型。使用枚举类更多地是与业务相关的概念挂钩。
Implement an Enumeration base class 实现一个枚举基类
The ordering microservice in eShopOnContainers provides a sample Enumeration base class implementation, as shown in the following example:
eShopOnContainers 的订单微服务提供了一个枚举基类的实现示例,如下所示:
/// <summary>
/// 强类型枚举类的抽象基类。
/// 在 DDD 中用于替代传统的 C# enum,以支持更丰富的面向对象特性(如添加方法、属性及状态控制流)。
/// </summary>
public abstract class Enumeration : IComparable
{
/// <summary>
/// 获取枚举项的名称。
/// </summary>
public string Name { get; private set; }
/// <summary>
/// 获取枚举项的唯一标识符 ID。
/// </summary>
public int Id { get; private set; }
/// <summary>
/// 受保护的构造函数,仅允许派生类初始化枚举实例的 ID 和名称。
/// </summary>
/// <param name="id">枚举项的唯一标识。</param>
/// <param name="name">枚举项的名称。</param>
protected Enumeration(int id, string name) => (Id, Name) = (id, name);
/// <summary>
/// 重写 ToString 方法,直接返回枚举项的名称以便于阅读和日志记录。
/// </summary>
/// <returns>枚举项的名称字符串。</returns>
public override string ToString() => Name;
/// <summary>
/// 通过反射获取指定枚举类 T 中定义的所有公共静态字段,并作为 IEnumerable 集合返回。
/// 常用于遍历该枚举类下的所有可用选项。
/// </summary>
/// <typeparam name="T">继承自 Enumeration 的具体枚举类。</typeparam>
/// <returns>包含所有静态枚举实例的可枚举集合。</returns>
public static IEnumerable<T> GetAll<T>() where T : Enumeration =>
typeof(T).GetFields(BindingFlags.Public | // 仅查找公共字段
BindingFlags.Static | // 仅查找静态字段
BindingFlags.DeclaredOnly) // 仅查找当前类声明的字段,排除继承的字段
.Select(f => f.GetValue(null)) // 获取静态字段的值(无需实例)
.Cast<T>(); // 将结果强制转换为具体的枚举类型 T
/// <summary>
/// 重写 Equals 方法,基于对象的实际类型和 ID 进行相等性比较,确保同类型且同 ID 的枚举被视为相等。
/// </summary>
/// <param name="obj">要比较的对象。</param>
/// <returns>如果类型和 ID 均匹配则返回 true,否则返回 false。</returns>
public override bool Equals(object obj)
{
// 使用模式匹配检查传入对象是否为 Enumeration 类型,若失败则直接返回 false
if (obj is not Enumeration otherValue)
{
return false;
}
// 检查两个对象的运行时类型是否完全一致(防止不同枚举类之间的误判)
var typeMatches = GetType().Equals(obj.GetType());
// 检查两个对象的 ID 是否相等
var valueMatches = Id.Equals(otherValue.Id);
// 只有当类型和 ID 都匹配时才认为两者相等
return typeMatches && valueMatches;
}
/// <summary>
/// 实现 IComparable 接口,基于 ID 的大小对枚举实例进行排序比较。
/// </summary>
/// <param name="other">要比较的另一个对象。</param>
/// <returns>比较结果整数(小于0、等于0或大于0)。</returns>
public int CompareTo(object other) => Id.CompareTo(((Enumeration)other).Id);
// ...其他实用工具方法...
}
You can use this class as a type in any entity or value object, as for the following CardType : Enumeration class:
你可以将这个类作为任何实体或值对象的类型来使用,比如下面的 CardType(卡片类型)枚举类:
/// <summary>
/// 支付卡类型枚举类。
/// 继承自 Enumeration 基类,以强类型的对象形式表示各种支持的卡片类型,而非使用传统的整数枚举。
/// </summary>
public class CardType : Enumeration
{
/// <summary>
/// 美国运通卡(American Express)。
/// </summary>
public static CardType Amex = new(1, nameof(Amex)); // 定义静态实例:ID 为 1,名称为 "Amex"
/// <summary>
/// Visa 信用卡/借记卡。
/// </summary>
public static CardType Visa = new(2, nameof(Visa)); // 定义静态实例:ID 为 2,名称为 "Visa"
/// <summary>
/// 万事达卡(MasterCard)。
/// </summary>
public static CardType MasterCard = new(3, nameof(MasterCard)); // 定义静态实例:ID 为 3,名称为 "MasterCard"
/// <summary>
/// 初始化一个新的 <see cref="CardType"/> 实例。
/// </summary>
/// <param name="id">卡类型的唯一数字标识符,用于数据库持久化。</param>
/// <param name="name">卡类型的字符串名称。</param>
public CardType(int id, string name)
: base(id, name) // 将 ID 和 Name 传递给抽象基类进行统一管理
{
}
}

浙公网安备 33010602011771号