<p>泛型数学依赖C# 11静态抽象接口成员和.NET 7+ BCL,必须显式约束where T : INumber(非INumber<T>等错误形式),且T须为具体实现类型;自定义类型需CRTP模式实现全部静态抽象成员,否则+、Zero等操作失败。</p>

泛型数学不是“加个 where T : struct 就能用运算符”,它依赖 C# 11 的静态抽象接口成员和 .NET 7+ 的 BCL 实现,缺一不可。没配对语言版本、SDK 或写错约束,+、T.Zero 全部报错。
INumber 约束必须显式写成 where T : INumber<t></t>
where T : INumber<t></t>常见错误是写成 where T : INumber(不存在)、where T : INumber<int></int>(类型不匹配)或漏掉泛型参数 T。编译器需要明确知道“这个 T 是自己实现 INumber<t></t> 的类型”,才能绑定 T.Zero、T.One 和 + 运算符。
-
INumber<t></t>是一个泛型接口,T必须是实现它的具体类型(如int、double、自定义结构体),不能是其他类型 - 内置数值类型(
int、long、float、double、decimal、BigInteger)在 .NET 7+ 中已实现INumber<t></t>,无需额外实现 - 若写成
where T : INumber<double></double>,编译器会认为“T要帮double实现接口”,但T不是double,导致T.Zero解析失败 - VS 可能只报 CA2260 警告而不阻止编译,但运行时调用
T.Parse()或T.Zero会直接失败(CS0315或空引用)
泛型方法里用 +、/ 前先确认接口覆盖范围
INumber<t></t> 提供 +、-、*、/、%、==、!=、T.Zero、T.One、T.CreateChecked() 等,但它不提供 Math.Sqrt、Math.Log、Math.Sin 等函数——这些属于浮点专用接口。
- 需要开方、对数、三角函数?改用
where T : IFloatingPoint<t></t>(支持float、double、Half),decimal不在此列 - 需要位运算(
&、|、~、<<)?用IBinaryInteger<t></t>(int、long、uint、BigInteger) - 只做加减、比较、零值构造?
INumber<t></t>足够;多加约束反而限制可用类型(比如加了IFloatingPoint<t></t>就不能传int) -
T.CreateChecked(n)用于安全地把整数转为T,失败抛异常;T.CreateTruncating截断,T.CreateSaturating溢出饱和——按需选,别默认用CreateChecked处理用户输入
自定义数值类型必须严格遵循 CRTP 模式
实现 INumber<myint></myint> 时,MyInt 必须把自己作为泛型参数传入,且所有静态抽象成员(Zero、One、operator + 等)都得是 public static 并返回 MyInt,否则泛型算法无法识别。
- 错误写法:
public struct MyInt : INumber<int></int>—— 这是在“替int实现”,不是“自己实现” - 正确写法:
public readonly struct MyInt : INumber<myint></myint>,且内部必须有public static MyInt Zero { get; }、public static MyInt operator +(MyInt l, MyInt r) - 若漏掉
operator +,即使加了约束,a + b仍报 “operator + cannot be applied” - 不要试图让自定义类型继承
int或double来复用行为——值类型不能继承,且泛型数学契约不跨类型传递
最易被忽略的是:泛型数学能力完全由编译期约束驱动,不是运行时反射或虚方法表查找。一旦约束写错(比如少了个 <t></t>、类型不匹配、漏静态成员),代码可能“看起来能编译”,但关键数学操作根本不可用——这种静默失效比编译失败更难排查。


















