如何在C#中模拟Sum/Product类型?ADT相关支持进展如何?
C# 中模拟 Sum(联合)类型与 Product(交叉)类型的实现及相关进展
一、用通用基类与标记接口手动模拟
可以通过密封基类实现Sum类型的约束,配合标记接口来限定字段子集(模拟Product类型),对应你提到的TypeScript思路:
Sum类型(联合类型)实现
定义密封基类作为所有可能类型的父类,通过私有构造限制外部扩展:
public sealed class Shape { private Shape() { } // 私有构造,仅内部子类可继承 public sealed class Circle : Shape { public double Radius { get; } public Circle(double radius) => Radius = radius; } public sealed class Rectangle : Shape { public double Width { get; } public double Height { get; } public Rectangle(double width, double height) { Width = width; Height = height; } } }
这里Shape就是一个Sum类型,它的实例只能是Circle或Rectangle。
用标记接口模拟Product类型(字段子集)
通过标记接口配合模式匹配,实现基类字段的子集收缩:
public interface IHasArea { } // 让子类实现标记接口 public sealed class Circle : Shape, IHasArea { /* 原有实现 */ } public sealed class Rectangle : Shape, IHasArea { /* 原有实现 */ } // 使用时通过接口缩小类型范围 public static double CalculateArea(IHasArea shape) { return shape switch { Shape.Circle c => Math.PI * c.Radius * c.Radius, Shape.Rectangle r => r.Width * r.Height, _ => throw new ArgumentException("不支持的形状类型") }; }
IHasArea相当于Product类型的约束,仅包含具备面积属性的Shape子类。
二、C# 官方已有的相关支持
C# 9及后续版本已提供类似Java 17密封记录的特性,简化代数数据类型(ADT)的实现:
- 密封类/密封记录:C# 9引入的密封类和记录类型,配合模式匹配可原生实现Sum类型。例如用密封记录:
public abstract sealed record Shape { public record Circle(double Radius) : Shape; public record Rectangle(double Width, double Height) : Shape; }
密封记录强制所有子类必须在同一文件中定义,避免外部扩展,完美贴合Sum类型的约束。
- 模式匹配增强:C# 9+的switch表达式、类型模式等特性,可无缝处理密封类型,实现类型安全的分支逻辑,替代传统的类型转换。
三、近年C# 在ADT领域的进展与规划
微软一直在推进代数数据类型的原生支持,核心目标是**区分联合(Discriminated Unions)**特性:
- 该特性已纳入.NET官方路线图,计划提供语法层面的Sum类型支持,无需手动定义密封类/记录。预期语法示例:
// 假想的区分联合语法 public type Shape = Circle(double Radius) | Rectangle(double Width, double Height);
- 目前该特性处于提案与设计迭代阶段,相关讨论在.NET的官方代码仓库中持续进行,后续版本的C#大概率会正式引入原生区分联合,进一步简化ADT的实现。
内容的提问来源于stack exchange,提问作者Tooster
相关产品推荐
相关产品推荐

