我正在尝试定义一个函数,该函数返回传入值的可为空版本,然后将其与布尔值一起应用。
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;
但我试图理解为什么通用版本不起作用。
首先。一旦您在两个单独的函数中分别对值引用类型使用类型约束
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;
}
}
}
如您所见,由于可空值/引用类型的实现方式不同,返回类型有所不同,因此您无法将其统一为单个函数。
免责声明:当我看到这个问题时,我深入研究了这一点,因为我一开始也很惊讶,这就是我通过查看降低的代码得出的解释。欢迎补充/更正。
我对此进行了研究,公平地说,我认为编译器将 A 参数视为任何类型参数,而不是一般的值类型参数,并且您希望让它认为它是一个可以为 null 的值类型参数。 目前,它在您的情况下将其视为布尔值,并且 ??不能应用于布尔值。
您可以向 Test 的通用类型添加约束
static A? Test<A>(A val, bool useNull) where A : struct
我们使用struct的原因是因为??设计用于可空值类型,而 struct 是可空值类型。