C# 泛型 notnull 约束不允许方法签名对于值类型可为空

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

我有这个代码片段

public static void Main()
{
    var t = new Test<uint>();

    t.Run(null);
}

public class Test<T> where T: notnull
{

    public void Run(T? value)
    {
        Console.WriteLine(value is null);
    }

}

我希望能够说 T 不可为空,但对于我的方法,我想接受可为空类型。然而这不起作用,因为 Run 的签名是

uint
而不是
uint?

引用类型的情况并非如此,它们按照我期望的方式工作,能够具有可为空的签名。

这里发生的事情不允许值类型具有可为空的方法签名。我发现如果我从 notnull 更改为 'struct' 它工作正常,但我希望能够接受引用和值类型。

c# generics notnull generic-constraints
1个回答
1
投票

这里发生了什么不允许值类型具有可为空的方法签名。

基本上没有办法在 IL 中表示这一点。

T?

Test<int>
的情况下,
Test<string>
的含义存在
根本性的
差异。在前一种情况下,
T?
表示完全不同的类型,
Nullable<int>
,而在后者中,
T?
表示“就 CLR 而言,
string
,但在编译时 null 分析期间允许 null”。

使用

T?
notnull
约束肯定会遇到一些奇怪的情况 - 约束很有用,但它绝对不是您想要或期望的。例如,您可以声明类型为 T?
field
,但最终它在 IL 中只是
T

public class Test<T> where T : notnull
{
    private T? field;

    public Test(T value) => field = value;
    public Test() {}

    public bool FieldIsNull => field == null;
}

class Program
{
    static void Main()
    {
        Test<string> test1 = new Test<string>();
        Console.WriteLine(test1.FieldIsNull); // True
        Test<int> test2 = new Test<int>();
        Console.WriteLine(test2.FieldIsNull); // False
    }
}

如果有什么安慰的话,ECMA C# 标准化小组正在努力“干净地”指定这一点 - 这非常棘手......

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