咨询C#中notnull约束与可空类型结合出现异常行为的原因
关于
notnull约束允许int?和string?实例化的原因 你引用的《Programming C# - 10.0》里对notnull约束的描述是准确的,但这个约束的行为和nullable上下文设置、C#里两种“可空类型”的本质差异直接相关,下面分点解释你的疑问:
1. 可空值类型int?完全符合notnull约束
int?是Nullable<int>的语法糖,它本身是一个值类型结构体,而notnull约束明确允许所有值类型(包括可空值类型)。这里的关键是:约束检查的是类型本身,而不是该类型的实例能否表示null状态。
你看到输出里System.Nullable1[System.Int32]的默认值是Null,这只是Nullable的默认状态(HasValue=false),但这个类型本身是值类型,完全满足notnull`约束的要求。
2. string?能通过编译是因为nullable上下文未启用
可空引用类型(比如string?)是C# 8.0引入的编译时注解,在运行时string?和string是完全相同的类型——这就是你输出里看到Type of T is System.String的原因。
notnull约束对可空引用类型的限制只在启用严格nullable上下文时生效:
- 如果你的项目没有设置
<Nullable>enable</Nullable>(默认是<Nullable>warning</Nullable>或关闭状态),编译器不会强制执行notnull约束对可空引用类型的检查,会自动将string?当作string处理,所以代码能正常编译运行。 - 一旦启用严格nullable上下文,编译器会直接抛出错误,禁止用
string?实例化带有notnull约束的泛型类。
3. notnull约束的双重作用逻辑
notnull约束的检查分为两个层面:
- 编译时:仅在启用nullable上下文时生效,会拦截可空引用类型传入,但允许值类型(包括可空值类型)。
- 运行时:对引用类型无任何检查(因为运行时没有可空引用类型的概念);对值类型,由于值类型本身不可能是
null引用(可空值类型的null是结构体的状态),所以也不会触发运行时错误。
内容的提问来源于stack exchange,提问作者Hanieh Sadeghi
相关产品推荐
相关产品推荐

