泛型类定义需确保类型参数T被实际使用且约束合理:从具体类(如NodeInt)改造为Node,将字段、方法中可变类型替换为T;有CompareTo操作时须加where T : IComparable;避免硬编码int,改用default(T);继承时子类须明确指定类型或保持开放。

泛型不是“加个T 往往意味着运行时异常风险,而过度约束又会锁死调用场景。
泛型类怎么定义才不白写
从具体类改起最稳妥:比如你有个 NodeInt 类只处理 int,先把它改成 Node<t></t>,再逐个替换字段和方法里的 int 为 T。别一上来就给 T 加 where T : class, new()——除非你真要用 new T() 或判空。
- 字段、属性、构造函数参数、返回值里出现的具体类型,只要可能变化,就该换成
T - 如果类里有
CompareTo操作,必须加where T : IComparable<t></t>,否则编译不过 - 避免在泛型类里硬编码
typeof(int)或default(int),改用default(T)或typeof(T) - 继承泛型基类时,子类要么指定具体类型(如
class IntNode : Node<int></int>),要么保持开放(class GenericNode<t> : Node<t></t></t>),不能写class BadNode : Node<t></t>(T未声明)
泛型方法的类型推断常被高估
编译器能推断 Swap(ref a, ref b) 的 T 是 int,是因为两个参数都是 int。但一旦参数类型不一致,或方法没参数,推断就失效。
- 带
ref/out参数的方法,推断只看传入变量的声明类型,不看实际值 -
void Log<t>(T value)</t>这种单参数方法,Log(42)推断为int,但Log(null)会报错——编译器无法确定T是哪个引用类型 - 重载时,编译器先做类型推断,再筛选候选方法;如果推断失败,哪怕有匹配的非泛型重载也不会选
- 方法内若需调用
T的实例方法(如t.ToString()),不用额外约束——所有类型都有ToString();但若调用t.CompareTo(),就必须加where T : IComparable<t></t>
泛型类里再写泛型方法容易踩坑
类本身有 T,方法又声明 T,就会触发警告 CS0693:内部 T 隐藏了外部 T。
- 正确做法是换名字,比如类是
GenericList<t></t>,方法就写成Convert<u>()</u>或Select<tresult>()</tresult> - 如果方法逻辑确实依赖类级
T(比如交换两个T字段),直接用类的T,不要额外声明类型参数 - 类级约束不会自动继承到方法上。即使
class Box<t> where T : IDisposable</t>,其方法void Close<t>()</t>里的T仍是独立的,不带IDisposable约束
最易忽略的是装箱/拆箱成本:对值类型使用无约束泛型(如 List<int></int>)是零开销的,但若误用了 object 或非泛型集合,int 就会反复装箱。泛型的价值不在语法炫技,而在让编译器在编译期就锁定类型行为——这要求你每加一个 T,都清楚它在哪被用、怎么被用、为什么不能是 object。



















