.NET 6中泛型可空性约束触发CS8714报错问题咨询
结论
你写的TKey?入参写法本身是合法的C#语法,但它的实际行为和多数开发者的直观预期存在差异,你遇到的CS8714警告是C#可空类型规则下的正常表现,不是语法错误。
核心规则说明
- 当泛型参数
TKey没有被明确约束为class(引用类型)或者struct(值类型)时,编译器对TKey?的解析是动态的:如果最终传入的TKey是引用类型,TKey?就代表对应类型的可空引用类型;如果最终传入的TKey是值类型,TKey?会被直接解析为Nullable<TKey>也就是int?这类可空值类型。 - 你给方法加的
where TKey : notnull约束,要求传入的类型参数必须是不可为null的类型——不可空引用类型、普通非Nullable值类型都满足要求,但int?这类可空值类型、可空引用类型都不满足该约束。 - 你调用方法时没有显式指定泛型类型,编译器会自动根据传入的两个参数推断共同的兼容类型:第一个参数是
int,第二个是int?,两者的共同兼容类型是int?,而int?不满足notnull约束,所以直接触发CS8714警告。你提到的显式指定类型参数为int仍然触发警告的问题,是你所用的17.2版本MSBuild对应的C#编译器的已知校验逻辑,后续编译器版本已经优化了这个场景下的误报,但核心规则没有变化。 - 如果你的实际需求是「支持传入任意不可空类型作为TKey,第二个参数可以是该类型对应的可空版本」,直接写无class/struct约束的
TKey?会遇到类型推断的问题,更稳妥的实现是写两个重载:一个加where TKey : struct值类型约束,第二个参数为TKey?;另一个加where TKey : class引用类型约束,第二个参数为TKey?。
官方文档对应规则位置
该行为属于C#可空引用类型特性下泛型可空性的标准设计规则,在官方C#语言规范的可空类型、泛型约束相关章节有明确说明,核心规则包括两点:
- 未明确约束为引用类型/值类型的泛型参数上的
?注解,属于类型参数相关的可空修饰,其最终具体类型由传入的类型参数属于值类型还是引用类型决定。 notnull约束对类型参数的可空性有强制要求,任何本身被定义为可空的类型(包括可空值类型、可空引用类型)都不能作为满足该约束的类型参数传入。
内容的提问来源于stack exchange,提问作者Norritt
相关产品推荐
相关产品推荐

