具有可空类型的 C# notnull 约束具有意外行为

问题描述 投票:0回答:1

我读过 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# constraints
1个回答
1
投票

这几天我一直在搜索这个问题,发现原因可能是:

  1. C# 中的 notnull 约束用于确保类型参数不为 null。根据官方文档,notnull 约束可以应用于值类型或不可为空的引用类型,但不能应用于可为空的引用类型

  2. 这段代码实例化了一个具有可为空类型 int 的泛型类?和字符串?它仍然有效。但是,不会对这些类型强制执行“notnull”约束,因为“notnull”约束仅在编译时强制执行,而不是在运行时强制执行。 从 C# 8.0 开始,开发人员可以将引用类型注释为可空(例如,字符串?),以向编译器指示该变量可以保留空值。此功能称为可为空引用类型。它旨在由编译器进行静态分析以发出警告,并且不会影响变量的实际运行时类型。 string和string的运行时类型?是相同的,因此它们都满足 notnull 约束。

  3. 即使有 notnull 约束,也允许可以为 null 的值类型,因为它们表示为 System.Nullable 结构,该结构本身就是一个值类型并且实际上不为 null。它只是能够通过 HasValue 属性来表示 null。那么代码编译是因为 int 吗?是一个可为空的结构体,并且这不是一个可为空的引用类型,而是一个值类型,它满足 notnull 约束。

还可以通过下面的链接查看 notnull 约束的文档。

https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/constraints-on-type-parameters

© www.soinside.com 2019 - 2024. All rights reserved.