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
相关产品推荐
相关产品推荐

