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

C#是否有类似Python 3 Optional的泛型?如何实现可存Regex或null的列表?

在C#中实现可存储Regex或null的强类型列表的最简方案

嘿,刚好你提到的需求在C#里有几种很直接的实现方式,我帮你拆解成最实用的几个方案,完美对应你想要的类似Python Optional或者区分联合的场景:

1. 最简洁的方案:用可空引用类型(C# 8.0+)

其实Regex本身是引用类型,默认List<Regex>也能加null,但这种写法没明确告诉其他开发者"这个列表允许存null",容易造成误解。C# 8.0引入的可空引用类型就完美对应Python的Optional,只需要在类型后面加个?,就能明确标注这个类型可以是实例或者null:

// 开启可空引用类型后,这个列表明明白白允许存Regex实例或者null
List<Regex?> regexList = new List<Regex?>();

// 用起来和普通List一样顺畅
regexList.Add(new Regex(@"^\d+$"));
regexList.Add(null);
regexList.Add(new Regex(@"^[a-z]+$"));

怎么开启可空引用类型?

只需要在你的项目文件(.csproj)里加一行配置就行:

<PropertyGroup>
  <Nullable>enable</Nullable>
</PropertyGroup>

开启后编译器还会帮你做静态检查,提前避免空引用异常,一举两得。

2. 更严谨的区分联合类型(C# 10.0+)

如果你想要完全消除歧义,明确表示列表元素要么是"有效的Regex实例",要么是"空值标记"(而不是隐式的null),那C# 10引入的记录类型区分联合就很合适:

// 定义一个专门的区分联合类型,把两种情况明确区分开
public record RegexOrNull
{
    // 私有构造函数,避免直接实例化基类
    private RegexOrNull() { }
    
    // 表示有效的Regex实例
    public sealed record ValidRegex(Regex Value) : RegexOrNull();
    // 表示空值的情况
    public sealed record NullValue() : RegexOrNull();
}

// 使用的时候就只能添加这两种合法的元素
List<RegexOrNull> regexList = new List<RegexOrNull>();
regexList.Add(new RegexOrNull.ValidRegex(new Regex(@"^\d+$")));
regexList.Add(new RegexOrNull.NullValue());

// 读取的时候用模式匹配,编译器会强制你处理两种情况,不会漏判
foreach (var item in regexList)
{
    switch (item)
    {
        case RegexOrNull.ValidRegex valid:
            Console.WriteLine($"找到有效正则:{valid.Value}");
            break;
        case RegexOrNull.NullValue:
            Console.WriteLine("这是一个空值标记");
            break;
    }
}

这种方式的好处是类型约束极强,不会有人不小心把其他类型的null或者无关对象塞进去,适合对类型严谨性要求高的场景。

3. 兼容旧版C#的轻量Union类

如果你的项目还在使用C# 10之前的版本,也可以自己写一个简单的Union类来模拟:

// 一个通用的双类型Union类
public class Union<T1, T2>
{
    public readonly T1? Value1;
    public readonly T2? Value2;
    public readonly bool IsValue1;

    private Union(T1 value)
    {
        Value1 = value;
        IsValue1 = true;
    }

    private Union(T2 value)
    {
        Value2 = value;
        IsValue1 = false;
    }

    // 隐式转换,方便直接赋值
    public static implicit operator Union<T1, T2>(T1 value) => new Union<T1, T2>(value);
    public static implicit operator Union<T1, T2>(T2 value) => new Union<T1, T2>(value);
}

// 使用的时候,用object或者一个空占位类型来代表null
List<Union<Regex, object>> regexList = new List<Union<Regex, object>>();
regexList.Add(new Regex(@"^\d+$"));
regexList.Add(null);

// 读取时判断类型
foreach (var item in regexList)
{
    if (item.IsValue1)
        Console.WriteLine($"正则表达式:{item.Value1}");
    else
        Console.WriteLine("空值");
}

不过这种方式不如前两种简洁,除非必须兼容旧版本,否则更推荐用前两种方案。

总结一下

  • 追求简洁和对应Python Optional的效果:选**List<Regex?> + 可空引用类型**,这是最直接的实现。
  • 追求极致的类型严谨性:选C# 10+的区分联合类型,完全消除歧义。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:40:10