where t : notnull 约束不能区分值类型和引用类型,它仅要求 t 是非可空类型(non-nullable type),即排除了 nullable 以及使用 ?> 标记的可空引用类型。这意味着传入的类型可以是任何非空的值类型(如 int、struct),也可以是任何非空的引用类型(如 class、string)。若需严格区分,必须结合 struct 或 class 约束。

如何同时满足非空与特定类型限制
要区分并限定具体类型,应组合使用 struct 或 class 约束。例如 where T : struct, notnull 强制为值类型且非空,而 where T : class, notnull 强制为非空引用类型。由于 struct 本身已隐含非空语义,notnull 在值类型约束中通常冗余,但在引用类型约束中则是必需的。

using System;
public class TypeChecker<t> where T : struct, notnull
{
public string Check()
{
// 编译通过:int, DateTime, custom structs
return "Value Type";
}
}
public class RefChecker<t> where T : class, notnull
{
public string Check()
{
// 编译通过:string, List<int>, custom classes
// 编译错误:object? (nullable reference)
return "Reference Type";
}
}</int></t></t>
不指定约束时的默认行为差异
如果不加任何约束,T 既可以是值类型也可以是引用类型,此时无法调用引用类型的成员(如虚方法)或值类型的默认构造函数(除非用 new())。notnull 的主要作用是消除编译器对 Nullable 的警告,确保在泛型逻辑中 T 始终有确定的内存布局或引用状态,但它不改变类型系统的分类本质。

using System;
public class GenericBase<t>
{
public void Process(T value)
{
// 如果 T 是 int,value 是栈上的值
// 如果 T 是 string,value 是堆上的引用
Console.WriteLine(value?.ToString() ?? "null");
}
}</t>
基于输入条件判断实际类型
当程序运行时需要知道 T 的具体类别,可以使用 typeof(T).IsValueType 进行运行时检查。这在处理混合类型的集合或需要针对不同类别执行不同逻辑时非常有用。注意,即使使用了 notnull,IsValueType 依然能准确区分传入的是值类型还是引用类型。











