C# 使用空合并运算符的隐式转换

C# 使用空合并运算符的隐式转换,c#,null,implicit-conversion,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)

我发现我的程序有一种奇怪的行为,经过进一步的分析,我发现我的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() ?
    }
}

此代码中的变量“b”计算为null。我不明白为什么它是空的

我在谷歌上搜索了一下,找到了这个问题的答案——有官方的说明

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

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

……事实并非如此

如果b是动态表达式,则结果类型为动态。在运行时,首先计算a。如果a不为null,则将a转换为动态,并将其作为结果。否则,将计算b,并将其作为结果

……事实并非如此

否则,如果A存在并且是可为null的类型,并且存在从b到A0的隐式转换,则结果类型为A0。在运行时,首先计算A。如果A不为null,则将A展开为类型A0,这将成为结果。否则,计算b并将其转换为类型A0,这将成为结果

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

否则,如果存在A并且存在从b到A的隐式转换,则结果类型为A。在运行时,首先计算A。如果A不为null,则A成为结果。否则,计算b并将其转换为类型A,这将成为结果

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

否则,如果b具有类型b且存在从a到b的隐式转换,则结果类型为b。在运行时,首先计算a。如果a不为null,则将a展开为类型A0(如果a存在且可为null),并将其转换为类型b,然后将其变为结果。否则,将计算b并将其变为结果

…b具有类型b,并且存在从a到b的隐式转换。 a被计算为null。因此,b应该被计算,b应该是结果

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


我遗漏了什么吗?

为什么希望null合并操作符返回
new B()
a
不是null,因此
a??new B()
计算结果为
a

现在我们知道将返回
a
,我们需要确定结果的类型(
T
),以及是否需要将
a
强制转换为
T

•否则,如果b具有类型b且存在来自的隐式转换 从a到B,结果类型为B。在运行时,首先计算a。如果 不为null,a被展开为A0类型(如果a存在且可为null) 和转换为类型B,这将成为结果。否则,B为 评估并成为结果

存在从
A
B
的隐式转换,因此
B
是表达式的结果类型。这意味着
A
将隐式转换为
B
。隐式运算符返回
null


事实上,如果您编写
var b=a??new b();
(注意
var
),您将看到编译器推断
b
为表达式返回的类型。

我们需要查看的部分是空合并表达式的编译时类型

否则,如果b具有类型b且存在从a到b的隐式转换,则结果类型为b。在运行时,首先计算a。如果a不为null,则将a展开为类型A0(如果a存在且可为null),并将其转换为类型b,然后将其变为结果。否则,将计算b并将其变为结果

要将其转换为伪代码:

public Tuple<Type, object> NullCoalesce<TA, TB>(TA a, TB b)
{
    ...
    else if (a is TB) // pseudocode alert, this won't work in actual C#
    {
        Type type = typeof(TB);
        object result;
        if (a != null)
        {
            result = (TB)a; // in your example, this resolves to null
        }
        else
        {
            result = b;
        }
        return new Tuple<Type, object>(type, result);
    }
    ...
}
公共元组NullCoalesce(TA a,TB b)
{
...
否则,如果(a是TB)//伪代码警报,这在实际的C中不起作用#
{
类型=类型(TB);
客观结果;
如果(a!=null)
{
result=(TB)a;//在您的示例中,它解析为null
}
其他的
{
结果=b;
}
返回新元组(类型、结果);
}
...
}
否则,如果b具有类型b并且存在来自a的隐式转换 对于B,结果类型为B。在运行时,首先计算a。如果 如果不为null,则a将展开为A0类型(如果a存在且可为null),并且 转换为类型B,这将成为结果。否则,B为 评估并成为结果

…b具有类型b,并且存在从a到b的隐式转换。a为 计算结果为null。因此,应计算b,且b应为空 结果呢

您的解释是错误的。没有任何说明在执行
null
检查之前执行
a
B
的转换。它说明
null
检查在转换之前完成

您的案例与此相符:

如果a不为空,则a将被展开为A0类型(如果a存在且为空) 可为空)和转换为类型B,此成为 结果


嗯,说明书上说(为了减少混淆,我改为
x
y
):

•否则,如果y具有类型y且存在从x到y的隐式转换,则结果类型为y。在运行时,首先计算x。如果x不为null,则将x展开为类型X0(如果x存在且可为null),并将其转换为类型y,然后将其变为结果。否则,计算y并将其变为结果

这种情况会发生。首先,检查左侧的
x
,它只是
a
,是否为
null
。但它本身不是
null
。然后
    A a = new A();
    B b = (B)a ?? new B();