我读过 C# 中的
notnull
约束,其中写道“这允许值类型或不可为空的引用类型,但不允许为空的引用类型。”
我尝试在下面的代码中检查此约束:
MyTestClass<int?> instance1 = new MyTestClass<int?>();
MyTestClass<string?> instance2 = new MyTestClass<string?>();
public class MyTestClass<T> where T : notnull
{
T Value { get; set; }
public MyTestClass()
{
Value = default(T);
if (Value == null)
Console.WriteLine($"Type of T is {typeof(T)} and its default value is 'Null'");
else
Console.WriteLine($"Type of T is {typeof(T)} and its default value is {Value}");
}
}
如您所见,我使用可为空类型
int?
(可为空值类型)和string?
(可为空引用类型)实例化了我的泛型类,它仍然对我有用。
它还为我打印这样的输出:
Type of T is System.Nullable`1[System.Int32] and its default value is 'Null'
Type of T is System.String and its default value is 'Null'
Type of T is System.Int32 and its default value is 0
Type of T is System.String and its default value is 'Null'"
它的行为是“字符串”?作为“字符串”并将两者检测为不可为空。 发生这些情况的原因是什么?
这几天我一直在搜索这个问题,发现原因可能是:
C# 中的 notnull 约束用于确保类型参数不为 null。根据官方文档,notnull 约束可以应用于值类型或不可为空的引用类型,但不能应用于可为空的引用类型
这段代码实例化了一个具有可为空类型 int 的泛型类?和字符串?它仍然有效。但是,不会对这些类型强制执行“notnull”约束,因为“notnull”约束仅在编译时强制执行,而不是在运行时强制执行。 从 C# 8.0 开始,开发人员可以将引用类型注释为可空(例如,字符串?),以向编译器指示该变量可以保留空值。此功能称为可为空引用类型。它旨在由编译器进行静态分析以发出警告,并且不会影响变量的实际运行时类型。 string和string的运行时类型?是相同的,因此它们都满足 notnull 约束。
即使有 notnull 约束,也允许可以为 null 的值类型,因为它们表示为 System.Nullable 结构,该结构本身就是一个值类型并且实际上不为 null。它只是能够通过 HasValue 属性来表示 null。那么代码编译是因为 int 吗?是一个可为空的结构体,并且这不是一个可为空的引用类型,而是一个值类型,它满足 notnull 约束。
还可以通过下面的链接查看 notnull 约束的文档。