如何从Nullable <t>明确</t>转换

时间:2014-12-11 12:53:53

标签: c# casting nullable implicit-cast

我定义了自定义值类型MyCustomValueType,隐式强制转换运算符从long到MyCustomValueType。

public struct MyCustomValueType
{
    private readonly long number;

    public MyCustomValueType(long? number)
    {
        this.number = number.GetValueOrDefault(0);
    }

    public static implicit operator MyCustomValueType(long number)
    {
        return new MyCustomValueType(number);
    }
}

然后编译器允许我执行以下操作:

// ...
long? value = null;
MyCustomValueType myCustomValueType = (MyCustomValueType)value;
Console.WriteLine(myCustomValueType);

在幕后,编译器将语句转换为:

MyCustomValueType myCustomValueType = ((long?)null).Value;

我想知道(或更好地说WHY)是怎么回事?为什么编译器甚至允许显式转换没有定义任何人。编译器适用的规则是什么?


我可能还应该提到,当MyCustomValueType仅定义用于强制转换的显式运算符时,也可以进行此类强制转换,例如:

public static explicit operator MyCustomValueType(long number)

但在这种情况下,我会以某种方式接受编译器的作用并理解它。隐式运算符的情况确实令人困惑。有人可以解释一下吗?

1 个答案:

答案 0 :(得分:5)

  

为什么编译器甚至允许显式转换没有定义任何人。编译器适用的规则是什么?

它应用了C#规范第6.4.2节中定义的提升转换

  

如果使用已定义的转换运算符从非可空值类型S转换为非可空值类型T,则存在提升转换运算符S?转换为T?。此提升转化运算符会执行从S?S的展开,然后是用户定义的从ST的转换,然后是T的换行到T?,除了空值S?直接转换为空值T?

所以你可以把它想象成:

long? value = null;
long tmp1 = (long) value;       // Unwrapping
MyCustomValueType tmp2 = tmp1;  // User-defined conversion
MyCustomValueType? tmp3 = tmp2; // Wrapping
MyCustomValueType myCustomValueType = (MyCustomValueType) tmp3; // Unwrapping

我不认为这是特别令人惊讶,说实话 - 特别是,如果你明白当声明的转换运算符显式时某些东西是可行的,那么当声明的转换运算符是隐式时,值得期望相同的用法是可行的。 (当然,不一定是反过来。)