首先:一旦你在两个单独的函数中分别为值引用类型使用类型约束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;
}
现在,为什么这不能在没有类型约束的单个方法中工作?
这与值类型的可空特性的实现方式有关,而不是引用类型.引用类型在设计上是可以为空的(这里的可为空功能的实现基本上只是一组属性,编译器可以使用这些属性来区分哪些可以为空,哪些不可以为空),而值类型不能为空.事实上,可为空值类型本身永远不会是null
.它是使用Nullable<T>
struct 和boxing实现的.
当您查看编译器使用例如Sharplab.io(这里是C#编译器从上面的代码生成的相关摘录)生成的lowered C#时,情况会变得更加清楚:
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;
}
}
}
正如您所看到的,由于实现可为空的值/引用类型的方式不同,返回类型也不同,因此您不能将其统一到单个方法中.
免责声明:当我看到这个问题时,我深入研究了这个问题,因为我一开始也对这种行为感到惊讶,这是我看了下面的代码后得出的解释.如果需要,可以随意添加/更正.