泛型类型参数必须是引用类型时应使用 where T : class 约束,它允许 string、接口、委托等引用类型,禁止 int、struct 等值类型,且可与 notnull 组合实现非空引用类型约束。

泛型类型参数必须是引用类型怎么写
用 class 约束,不是指“必须是 class 声明的类”,而是表示“必须是引用类型(包括 class、interface、delegate、record、string 等),不能是 int、bool、struct 等值类型”。
常见错误现象:T 被传入 int 时编译失败,但没写约束就等到调用处才报错,定位困难。
-
class约束允许string、IEnumerable<T>、自定义接口,也允许null - 不能和
struct约束共存;若同时需要“非 null 引用”,得额外加where T : class, notnull - 性能影响极小——编译期检查,不产生运行时开销
示例:
public static void PrintName<T>(T item) where T : class
{
Console.WriteLine(item?.ToString() ?? "null");
}泛型必须实现某个接口怎么约束
直接用接口名作为约束,支持多接口,顺序无关,也不要求接口必须是 public。
使用场景:想在泛型方法里调用 CompareTo、Dispose 或自定义契约方法。
- 接口约束不要求类型“显式继承”该接口——只要满足成员签名(如隐式实现),但 C# 泛型只认显式声明的接口,不支持 Duck Typing
- 若接口带泛型参数(如
IComparable<T>),需保持一致:where T : IComparable<T> - 多个接口用逗号分隔:
where T : IDisposable, ICloneable, new()
示例:
public static int CompareFirst<T>(T a, T b) where T : IComparable<T>
{
return a.CompareTo(b);
}为什么 where T : new() 必须配合其他约束一起用
new() 约束要求类型有无参公共构造函数,但它本身不暗示值类型或引用类型——struct 和 class 都可能满足。单独用容易踩坑。
常见错误现象:给 new() 约束传入 string,编译失败(string 没无参构造);或传入没有 public 无参构造的 class,同样失败。
-
new()不能单独存在,必须和其他约束组合,否则编译器会警告 CS0417:“'new()' 约束无法与 'class' 或 'struct' 约束共存”——等等,不对,它其实可以单独用,但毫无意义:因为new()允许struct(如int)也满足,而你很可能想 new 出一个对象实例,结果却意外接受int导致逻辑错乱 - 更安全的写法是
where T : class, new()或where T : struct, new() - 注意:记录类型(
record)默认有 public 无参构造,满足new();但record struct不行(C# 12 起才支持无参构造)
泛型约束里能用 notnull 替代 class 吗
不能替代,但可补充。notnull 是 C# 8 引入的可空引用类型约束,只在开启 #nullable enable 时生效,且不阻止值类型传入。
使用场景:你希望泛型参数非 null,又不想强制它是引用类型(比如想支持 DateTime 这种非 null 值类型)。
-
notnull允许int、DateTime、string(非 null 上下文)、MyClass(非 null),但不允许string? -
class禁止所有值类型;notnull不禁止值类型——这是根本区别 - 两者可共存:
where T : notnull, class表示“非 null 的引用类型”,比单纯class更严格 - 兼容性注意:.NET Standard 2.0 不支持
notnull,需 .NET Core 3.0+ 或 .NET 5+
真正容易被忽略的是:约束生效依赖编译器对可空性的推断,而不是运行时检查——如果项目没开 nullable,notnull 约束形同虚设。










