C#泛型场景下如何传入整数值而非类型以消除FixedArray冗余代码
方案1:C# 11+ 数字泛型参数(最优解)
如果你可以升级到C# 11/.NET 7及以上版本,直接用语言内置的数值类型作为泛型参数特性,完全不需要自定义任何VM类,零冗余代码:
sealed class FixedArray<T, Length> : IStructuralComparable where T : struct where Length : INumber<int> { public T[] array { get; init; } public FixedArray() { // Length是编译期常量,JIT会直接优化成固定长度数组分配,无任何运行时开销 array = new T[Length]; } public int CompareTo(object? other, IComparer comparer) => ((IStructuralComparable)array).CompareTo(other, comparer); }
使用的时候直接传长度值就行,比你原来的写法更简洁:
var int2 = new FixedArray<int, 2>(); // 等价你原来的FixedArray<int, VM2> var double3 = new FixedArray<double, 3>(); var ushort6 = new FixedArray<ushort, 6>();
方案2:低版本C# 用源生成器自动生成VM类
如果要兼容旧版本框架,不需要手动写每个VMxxx的实现,写一个简单的C#源生成器,扫描你代码里用到的所有FixedArray<T, VMxxx>的长度,或者预定义你需要的长度列表(就是你补充的1、2、3...24这些值),自动生成所有实现了IVM接口的结构体代码,完全避免手动写样板代码。
生成的代码可以直接标记为internal,对你的业务代码透明,你只需要维护一份长度列表就行,新增长度只要改列表,不需要手动加类。
方案3:范围值的处理
针对你补充的1-2、1-3这类范围类型的需求,可以单独加一套泛型参数逻辑:
// 范围接口定义 interface IVMRange { int Min { get; } int Max { get; } } // 固定长度和范围可以二选一作为泛型参数,用约束区分逻辑 sealed class FixedArray<T, TLength> : IStructuralComparable where T : struct where TLength : new() { public T[] array { get; init; } public FixedArray() { var lenParam = new TLength(); if (lenParam is IVM fixedLen) { array = new T[fixedLen.Value]; } else if (lenParam is IVMRange range) { // 你自己的范围场景初始化逻辑 array = new T[range.Max]; } } // 其他方法省略 }
同样范围的VM类也可以用源生成器批量生成,不需要手动编写。
原有实现的优化提示
你现在的实现其实已经可以满足需求,所有VM类的无参构造和Value属性都是编译期常量,JIT在运行时会完全优化掉new VM().Value的调用,直接替换成对应常量,不会有额外的性能开销,唯一的冗余就是VM类的手写代码,用源生成器就能解决。
内容的提问来源于stack exchange,提问作者malat
相关产品推荐
相关产品推荐

