You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何创建唯一且只读的枚举子集集合?

问题描述

我定义了一个大型枚举:

public enum RetirementTypes
{
   k401 = 1,
   b403 = 2,
   b457 = 3,
   SimpleIRA = 4,
   Simple401k = 5,
   TIRA = 6,
   RIRA = 7,
   RothIRA = 8,
   Solo401k = 9,
   SEPIRA = 10,
   FA = 11,
   VA = 12,
   ESOP = 14,
   PERA = 15,
   VL = 16,
   SpousalIRA = 17,
   BIRA = 19,
   OtherRetirement = 22,
   TSP = 23,
   OtherIra = 24,
   BRoth = 33
   // 其他枚举项
}

我希望在部分组件中定义该枚举的子集,要求:

  • 子集是常量/只读的
  • 包含唯一值
  • 最好能在编译时发现重复值问题

目前我用IReadOnlyCollection来定义子集,但存在重复值无法提前发现的问题,比如:

IReadOnlyCollection<RetirementTypes> RETIREMENT_IRA_TYPES = [
    RetirementTypes.SEPIRA, 
    RetirementTypes.BIRA, 
    RetirementTypes.RothIRA, 
    RetirementTypes.OtherIra,
    RetirementTypes.RIRA, 
    RetirementTypes.SpousalIRA, 
    RetirementTypes.OtherIra, // 重复项
    RetirementTypes.RothIRA    // 重复项
];

这个子集用于查询过滤,比如:

iw.WbRetirements.Where(x => x.Owner == (int)OwnerType.Self && RETIREMENT_IRA_TYPES.Contains((RetirementTypes)x.RetirementPlanType)).Sum(b => b.Balance);

请问有没有办法实现满足要求的唯一、只读集合?

解决方案

1. 只读HashSet + 编译时分析器(最优解)

实现方式:

用HashSet<RetirementTypes>存储子集,再通过AsReadOnly()转为只读集合,保证运行时唯一性;同时编写自定义Roslyn分析器,在编译时扫描集合初始化代码,检测重复枚举值。

代码示例:

// 定义只读的唯一集合
public static readonly IReadOnlySet<RetirementTypes> RETIREMENT_IRA_TYPES = new HashSet<RetirementTypes>
{
    RetirementTypes.SEPIRA,
    RetirementTypes.BIRA,
    RetirementTypes.RothIRA,
    RetirementTypes.OtherIra,
    RetirementTypes.RIRA,
    RetirementTypes.SpousalIRA
}.AsReadOnly();

编译时检查:

如果团队有能力,可以编写简单的Roslyn分析器,标记需要检查的集合(比如用自定义属性),扫描初始化列表中的重复值并触发编译错误。如果没有自定义分析器的条件,也可以在CI流程中添加脚本,扫描这类集合定义,发现重复就终止构建。

2. 静态类常量集合(编译时自动检测重复)

如果子集数量固定且不多,可以用静态类的常量字段定义,IDE会自动提示重复的常量赋值:

public static class IraRetirementTypes
{
    public const RetirementTypes SEPIRA = RetirementTypes.SEPIRA;
    public const RetirementTypes BIRA = RetirementTypes.BIRA;
    public const RetirementTypes RothIRA = RetirementTypes.RothIRA;
    public const RetirementTypes OtherIra = RetirementTypes.OtherIra;
    public const RetirementTypes RIRA = RetirementTypes.RIRA;
    public const RetirementTypes SpousalIRA = RetirementTypes.SpousalIRA;

    // 提供只读集合供查询使用
    public static readonly IReadOnlySet<RetirementTypes> All = new HashSet<RetirementTypes>
    {
        SEPIRA, BIRA, RothIRA, OtherIra, RIRA, SpousalIRA
    }.AsReadOnly();
}

使用时直接调用IraRetirementTypes.All.Contains(...)即可,重复定义常量会立即被IDE识别并报错。

3. 自定义只读集合类(运行时快速报错)

创建一个自定义的只读集合类,在构造函数中检查重复值,初始化时发现重复就抛出异常:

public class UniqueReadOnlyEnumSet<T> : IReadOnlySet<T> where T : Enum
{
    private readonly HashSet<T> _innerSet;

    public UniqueReadOnlyEnumSet(params T[] items)
    {
        _innerSet = new HashSet<T>(items);
        if (_innerSet.Count != items.Length)
        {
            throw new ArgumentException("集合中存在重复的枚举值");
        }
    }

    // 实现IReadOnlySet<T>接口方法,委托给_innerSet
    public bool Contains(T item) => _innerSet.Contains(item);
    public bool IsProperSubsetOf(IEnumerable<T> other) => _innerSet.IsProperSubsetOf(other);
    public bool IsProperSupersetOf(IEnumerable<T> other) => _innerSet.IsProperSupersetOf(other);
    public bool IsSubsetOf(IEnumerable<T> other) => _innerSet.IsSubsetOf(other);
    public bool IsSupersetOf(IEnumerable<T> other) => _innerSet.IsSupersetOf(other);
    public bool Overlaps(IEnumerable<T> other) => _innerSet.Overlaps(other);
    public bool SetEquals(IEnumerable<T> other) => _innerSet.SetEquals(other);
    public IEnumerator<T> GetEnumerator() => _innerSet.GetEnumerator();
    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}

使用方式:

public static readonly UniqueReadOnlyEnumSet<RetirementTypes> RETIREMENT_IRA_TYPES = new(
    RetirementTypes.SEPIRA,
    RetirementTypes.BIRA,
    RetirementTypes.RothIRA,
    RetirementTypes.OtherIra,
    RetirementTypes.RIRA,
    RetirementTypes.SpousalIRA
);

这种方式虽然是运行时检查,但能在程序启动或单元测试阶段快速发现重复问题。

4. 源生成器(进阶编译时方案)

编写C#源生成器,通过自定义属性标记枚举子集,比如[EnumSubset(typeof(RetirementTypes), "SEPIRA,BIRA,RothIRA")],生成器解析属性参数后自动生成包含唯一值的只读集合代码,同时在生成过程中检查重复值,若存在重复则触发编译错误。

内容的提问来源于stack exchange,提问作者D A

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 08:08:26