我读过有关notnullC# 中的约束的内容,其中写道“这允许值类型或不可为空的引用类型,但不允许可为空的引用类型。” (引用自《Programming C# - 10.0 By Ian Griffiths》)
我尝试在下面的代码中检查这个约束:
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}");
}
}
Run Code Online (Sandbox Code Playgroud)
如您所见,我使用可为空类型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'"
Run Code Online (Sandbox Code Playgroud)
它的行为是“字符串?” 作为“字符串”并将两者检测为不可为空。发生这些情况的原因可能是什么?
这几天我一直在搜索这个问题,发现原因可能是:
C# 中的 notnull 约束用于确保类型参数不为 null。根据官方文档,notnull 约束可以应用于值类型或不可为空的引用类型,但不能应用于可为空的引用类型
这段代码实例化了一个具有可为空类型 int 的泛型类?和字符串?它仍然有效。但是,不会对这些类型强制执行“notnull”约束,因为“notnull”约束仅在编译时强制执行,而不是在运行时强制执行。从 C# 8.0 开始,开发人员可以将引用类型注释为可空(例如,字符串?),以向编译器指示该变量可以保留空值。此功能称为可为空引用类型。它旨在由编译器进行静态分析以发出警告,并且不会影响变量的实际运行时类型。string和string的运行时类型?相同,因此它们都满足 notnull 约束。
即使有 notnull 约束,也允许可为 null 的值类型,因为它们表示为 System.Nullable 结构,该结构本身就是值类型并且实际上不为 null。它只是能够通过 HasValue 属性来表示 null。那么代码编译是因为 int 吗?是一个可为空的结构体,并且这不是一个可为空的引用类型,而是一个值类型,它满足 notnull 约束。
另外,通过下面的链接您可以查看 notnull 约束的文档。
小智 7
正如所定义的,约束notnull“将类型参数限制为不可为空的类型。该类型可以是值类型或不可为空的引用类型”。[ 1 ]
该约束可用于可空启用上下文中的代码,并且在编译时检查与约束不匹配的类型参数(即string?,int[]?),并创建警告而不是错误,特别是CS8714: Nullability of type argument doesn't match 'notnull' constraint.
因此,程序将在打破notnull约束时进行编译,但会在可能的情况下发出编译时警告。值得一提的是,它只会在可能的情况下发出警告,因为“包含 notnull 约束的通用声明可以在可为 null 的不经意上下文中使用,但编译器不会强制执行该约束。” [ 1 ]
因此,可为 null 的引用类型可以作为有效类型参数传递给使用notnull约束指定的类型参数,但不应该这样做。除非演示没有在上下文中运行,否则应该在演示中发出警告#nullable enable。
资料来源: