6

基本上为什么以下在 C# 中无效?我可以找到很多好的用途,实际上可以通过创建我自己的可为空的结构类来修复它,但是 C# 规范(以及编译器)为什么以及如何阻止它?

下面是我正在谈论的部分示例。

struct MyNullable<T> where T : struct
{
    public T Value;
    public bool HasValue;

    // Need to overide equals, as well as provide static implicit/explit cast operators
}

class Program
{
    static void Main(string[] args)
    {
        // Compiles fine and works as expected
        MyNullable<Double> NullableDoubleTest;
        NullableDoubleTest.Value = 63.0;

        // Also compiles fine and works as expected
        MyNullable<MyNullable<Double>> NullableNullableTest;
        NullableNullableTest.Value.Value = 63.0;

        // Fails to compile...despite Nullable being a struct
        // Error: The type 'double?' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'ConsoleApplication1.MyNullable<T>'
        MyNullable<Nullable<Double>> MyNullableSuperStruct;
    }
}
4

2 回答 2

9

它是一个struct. 它只是不满足值类型泛型类型参数约束。从语言规范的 10.1.5 开始:

值类型约束指定用于类型参数的类型参数必须是不可为空的值类型。所有具有值类型约束的不可空结构类型、枚举类型和类型参数都满足此约束。请注意,尽管归类为值类型,但可为空的类型(第 4.1.10 节)不满足值类型约束。

所以,这where T : struct并不意味着你认为它意味着什么。

基本上为什么以下在 C# 中无效?

因为where T : struct只能满足T不可为空的值类型。Nullable<TNonNullableValueType>不满足这个约束。

编译器为什么以及如何阻止它?

为什么?要与规范一致。如何?通过执行句法和语义分析并确定您提供了T不满足泛型类型约束的泛型类型参数where T : struct

[I] 可以通过创建我自己的可为空的结构类来修复它,但是

不,您的版本无法修复它。它基本上与除了编译器没有进行特殊处理之外完全相同Nullable<T>,并且您将导致编译器的实现不会装箱的一些装箱。

我可以找到很多好的用途

真的吗?如?请记住,基本思想Nullable<T>是有一个存储位置可以包含T或可以表示“缺少值”。嵌套这个有什么意义?也就是说,有什么意义Nullable<Nullable<T>>?它甚至没有概念意义。这可能是它被禁止的原因,但我只是在推测(Eric Lippert 已经确认这种推测是正确的)。例如,什么是int??? 它代表一个存储位置,代表值丢失或者是一个int?,它本身就是一个存储位置,代表值丢失或者是一个int?什么用途?

于 2012-04-17T18:12:19.910 回答
2

结构约束允许空值的一个原因是我们希望能够T?在泛型方法中使用。如果struct允许可空值类型,编译器将不得不禁止T?.

在其他情况下,可空类型也必须在编译器中进行特殊处理:

  • null 关键字必须可以隐式转换为可空类型;这对于值类型是不可能的。
  • 可空值类型可以与空关键字进行比较;对于不可为空的值类型,此比较始终返回 false。
  • 可空值类型与??运算符一起使用;非空值没有。
于 2012-04-17T18:19:09.877 回答