返回可为空泛型类型的函数未返回正确的类型

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

我正在尝试定义一个函数,该函数返回传入值的可为空版本,然后将其与布尔值一起应用。

using System;

#nullable enable

public class Program
{
    public static void Main()
    {
        Console.WriteLine(Test(true, true) ?? false);
    }
    
    public static A? Test<A>(A val, bool useNull) =>
        useNull ? default(A?) : val;
}

但是,这给了我错误:

编译错误(第 11 行,第 21 列):运算符 '??'不能应用于“bool”和“bool”类型的操作数

但是我不太清楚为什么会给出这个错误 - 毕竟

Test()
应该返回类型
bool?
,而不是
bool
,所以使用
??
应该是完全合法的。

这是 C# 可空值功能中的错误,还是我误解了它的工作原理?

就其价值而言,如果我将

Test()
重写为非通用的,它似乎可以工作:

public static bool? Test(bool val, bool useNull) => 
    useNull ? null : val;

但我试图理解为什么通用版本不起作用。

c# nullable
2个回答
0
投票

首先。一旦您在两个单独的函数中分别对值引用类型使用类型约束

class
struct
,就可以使其工作。

namespace MyProgram;

public class Program
{
    public static void Main()
    {
        Console.WriteLine(NullableValueType(true, true) ?? false);
        Console.WriteLine(NullableReferenceType(new object(), true) ?? false);
    }

    public static A? NullableValueType<A>(A val, bool useNull) where A : struct
        => useNull ? null : val;


    public static A? NullableReferenceType<A>(A val, bool useNull) where A : class
            => useNull ? null : val;
}

现在为什么这不能在没有类型限制的单个函数中工作?

嗯,这与值类型与引用类型相比的 Nullable 特性的实现方式有关。引用类型在设计上可以为空,而值类型不能为空。事实上,可为 null 的值类型本身永远不是

null
。它是通过使用
Nullable<T>
结构和 boxing 来实现的。

当您查看编译器使用例如生成的 lower C# 时,情况会变得更清楚Sharplab.io

namespace MyProgram
{
    public class Program
    {
        public static void Main()
        {
            Console.WriteLine(NullableValueType(true, true).GetValueOrDefault());
            Console.WriteLine(NullableReferenceType(new object(), true) ?? ((object)false));
        }

        public static Nullable<A> NullableValueType<A>(A val, bool useNull) where A : struct
        {
            return useNull ? null : new Nullable<A>(val);
        }

        [System.Runtime.CompilerServices.NullableContext(1)]
        [return: System.Runtime.CompilerServices.Nullable(2)]
        public static A NullableReferenceType<A>(A val, bool useNull) where A : class
        {
            return useNull ? null : val;
        }
    }
}

如您所见,由于可空值/引用类型的实现方式不同,返回类型有所不同,因此您无法将其统一为单个函数。

免责声明:当我看到这个问题时,我深入研究了这一点,因为我一开始也很惊讶,这就是我通过查看降低的代码得出的解释。欢迎补充/更正。


0
投票

我对此进行了研究,公平地说,我认为编译器将 A 参数视为任何类型参数,而不是一般的值类型参数,并且您希望让它认为它是一个可以为 null 的值类型参数。 目前,它在您的情况下将其视为布尔值,并且 ??不能应用于布尔值。

您可以向 Test 的通用类型添加约束

static A? Test<A>(A val, bool useNull) where A : struct

我们使用struct的原因是因为??设计用于可空值类型,而 struct 是可空值类型。

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