T是泛型类型参数占位符,非固定类型或关键字;编译时替换为具体类型生成专用代码,兼顾类型安全与性能,避免object装箱和dynamic失去编译检查。

T 就是你用的时候才填进去的类型占位符,不是某种固定类型,也不是关键字,它就是个“代号”。 比如 List 本身不能直接 new,你必须写成 List 或 List —— 这时 T 才被替换成具体类型,编译器才真正生成对应代码。
为什么非得用 T,不用 object 或 dynamic?
用 object 看似通用,但会引发两个硬伤:
- 值类型(如
int)存进List会装箱,取出来再拆箱,性能损耗明显,尤其高频操作时 - 类型不安全:你往里加了个
string,编译器不管;但后面按int强转,运行时直接抛InvalidCastException -
dynamic更糟:完全绕过编译检查,连 IDE 提示、重构支持都丢了
而 List 在编译期就锁死类型——list.Add("abc") 往 List 里加,根本过不了编译。
T 可以换成别的名字吗?
完全可以。T 只是约定俗成的单字母缩写,源于 “Type”。你写 class Box、class Repository 甚至 class Pipe 都合法。
但要注意:
- 多个泛型参数时,务必用有意义的名,比如
Dictionary,没人会写Dictionary - 接口或委托中常见命名习惯:
IComparer、Predicate、Func - 自定义泛型类如果只用一个参数,坚持用
T最省事,团队也一眼能懂
泛型方法里的 T 怎么用?
泛型方法把类型选择权交给调用方,而不是类本身。例如:
public static T GetFirst(IList list) { return list.Count > 0 ? list[0] : default; }
调用时可以显式指定:GetFirst,也可以让编译器推断:GetFirst(myInts)(前提是 myInts 是 List 这类明确类型的集合)。
容易踩的坑:
- 别在泛型方法里对
T做==或!=判断(值类型/引用类型行为不一致),改用EqualityComparer.Default.Equals(a, b) - 如果需要约束
T必须有无参构造函数,得加where T : new() - 别试图在方法内写
typeof(T) == typeof(int)来做运行时分支——这违背泛型本意,也影响 JIT 优化
真正关键的一点是:T 不是运行时“动态决定”的类型,而是编译时由你填写后,CLR 为每种实际类型(int、Customer、Guid)生成独立的专用版本。所以它既类型安全,又没装箱开销——这不是妥协出来的方案,是 C# 泛型设计的底层逻辑。









