使用null-coalescing运算符进行隐式转换

Mir*_*rek 6 c# null implicit-conversion

我发现了我的程序的一个奇怪的行为,经过进一步的分析,我发现在我的C#知识或其他地方可能存在错误.我相信这是我的错,但我无法在任何地方找到答案......

public class B
{
    public static implicit operator B(A values) 
    {
        return null; 
    }
}
public class A { }

public class Program
{
    static void Main(string[] args)
    {
        A a = new A();
        B b = a ?? new B();
        //b = null ... is it wrong that I expect b to be B() ?
    }
}
Run Code Online (Sandbox Code Playgroud)

此代码中的变量"b"被计算为null.我不明白为什么它是null.

我用谷歌搜索并在这个问题中找到了一个响应- 使用官方规范隐式转换Null-Coalescing运算符结果.

但是按照这个规范,我找不到"b"为空的原因:(也许我读错了,在这种情况下我为垃圾邮件道歉.

如果A存在且不是可空类型或引用类型,则发生编译时错误.

......事实并非如此.

如果b是动态表达式,则结果类型是动态的.在运行时,首先评估a.如果a不为null,则a将转换为dynamic,这将成为结果.否则,评估b,结果成为结果.

......事实并非如此.

否则,如果A存在且是可空类型,并且存在从b到A0的隐式转换,则结果类型为A0.在运行时,首先评估a.如果a不为null,则打开a以键入A0,这将成为结果.否则,b被评估并转换为类型A0,这就成了结果.

...存在,从b到A0的隐式转换不存在.

否则,如果A存在且从b到A存在隐式转换,则结果类型为A.在运行时,首先计算a.如果a不为null,则a成为结果.否则,b被评估并转换为类型A,这就是结果.

...存在,从b到A的隐式转换不存在.

否则,如果b具有类型B并且从a到B存在隐式转换,则结果类型为B.在运行时,首先计算a.如果a不为null,则打开a以键入A0(如果A存在且可为空)并转换为类型B,这将成为结果.否则,b被评估并成为结果.

... b具有类型B,并且从a到B存在隐式转换.a被评估为null.因此,应评估b,结果应为b.

否则,a和b不兼容,并发生编译时错误.不会发生

我错过了什么吗?

dca*_*tro 8

为什么你期望null合并运算符返回new B()a不为null,因此a ?? new B()计算结果为a.

现在我们知道a将返回,我们需要确定result(T)的类型以及是否需要转换aT.

•否则,如果b具有类型B并且从a到B存在隐式转换,则结果类型为B.在运行时,首先计算a.如果a不为null,打开a以键入A0(如果A存在且可为空)并转换为类型B,这将成为结果.否则,b被评估并成为结果.

Ato到存在隐式转换B,B表达式的结果类型也是如此.这意味着a将隐含地投入B.你的隐式运算符返回null.

实际上,如果你写var b = a ?? new B();(注意var),你会看到编译器推断B为表达式返回的类型.

  • @KendallFrey足够接近它.只有当第一个和第二个操作数解析为相同类型(或类型的可空和非可空版本)时,`??`才有效.第一个操作数"a"与null进行比较,然后*转换为类型为"B"*,此时隐式转换将其转换为"null".为此,不需要将其分配给任何东西. (2认同)

Jep*_*sen 1

好吧,规范说(我在这里更改为x和 ,y以减少混淆):

\n\n
\n

\xe2\x80\xa2 否则,如果 y 具有类型 Y 并且存在从 x 到 Y 的隐式转换,则结果类型为 Y。在运行时,首先计算 x。如果 x 不为 null,则 x 将解包为类型 X0(如果 X 存在且可为空)并转换为类型 Y,这将成为结果。否则,计算 y 并成为结果。

\n
\n\n

有时候是这样的。首先,检查左侧x,即。但它本身并不是这样。然后将使用左侧。然后运行隐式转换。其类型结果是...。anullnullBnull

\n\n

请注意,这不同于:

\n\n
    A a = new A();\n    B b = (B)a ?? new B();\n
Run Code Online (Sandbox Code Playgroud)\n\n

在这种情况下,左操作数是一个表达式 ( x),它null本身就是一个表达式 ( ),结果成为右侧 ( y)。

\n\n

也许引用类型之间的隐式转换应该返回null(如果并且)仅当原始类型是 时null,作为一个好的实践?

\n\n
\n\n

我想编写规范的人可以这样做(但没有):

\n\n
\n

\xe2\x80\xa2 否则,如果 y 具有类型 Y 并且存在从 x 到 Y 的隐式转换,则结果类型为 Y。在运行时,首先计算 x 并将其转换为类型 Y。如果该输出conversion 不为 null,输出即为结果。否则,计算 y 并成为结果。

\n
\n\n

也许这样会更直观?无论转换的输入是否存在,它都会强制运行时调用隐式转换null。如果典型的实现能够快速确定这一点,那么成本应该不会太高null \xe2\x86\x92 null

\n