以下代码在Main函数的第二行标题中给出了错误。
public class P {}
public class B : P {}
public class A : P {}
void Main()
{
P p = GetA()??GetB();
}
public A GetA()
{
return new A();
}
public B GetB()
{
return new B();
}
像这些
这样的简单调整 p = (P)GetA()??GetB();
or
p = GetA()??(P)GetB();
作品。
我很好奇为什么编译器不明白两者都是左侧容器的子类并允许没有强制转换的操作?
答案 0 :(得分:6)
左侧的参数类型必须与右侧的类型兼容,反之亦然。换句话说,必须存在从B
到A
或从A
到B
的隐式转换。
var a = x ?? y;
在上文中,如果存在从y
到x
的隐式转换,则x
的类型将成为表达式的类型。如果没有从y
到x
的隐式转换,但存在从x
到y
的隐式转换,则y
的类型将成为类型的表达。如果两个方向都没有转换,那么繁荣;编译错误。来自规范:
表达式的类型a ?? b取决于操作数类型之间可用的隐式转换。按优先顺序排列,类型为?? b是A0,A或B,其中A是a的类型,B是b的类型(假设b具有类型),如果A是可空类型,则A0是A的基础类型,否则A 。具体来说,一个?? b按如下方式处理:
•如果A不是可空类型或引用类型,则会发生编译时错误。
•如果A是可空类型,并且从b到A0存在隐式转换,则结果类型为A0。在运行时,首先评估a。如果a不为null,则打开a以键入A0,这将成为结果。否则,b被评估并转换为类型A0,这就是结果。
•否则,如果从b到A存在隐式转换,则结果类型为A.在运行时,首先计算a。如果a不为null,则a成为结果。否则,b被评估并转换为类型A,这就是结果。
•否则,如果b具有类型B并且存在从A0到B的隐式转换,则结果类型为B.在运行时,首先计算a。如果a不为null,则打开a以键入A0(除非A和A0是相同的类型)并转换为类型B,这将成为结果。否则,b被评估并成为结果。
•否则,a和b不兼容,并发生编译时错误。
答案 1 :(得分:1)
我很好奇为什么编译器不明白两者都是左侧容器的子类并允许没有强制转换的操作?
因为这样就可以了:
public class SqlConnection : object {}
public class Random : object {}
public SqlConnection GetA() { return new SqlConnection(); }
public Random GetB() { return new Random(); }
void Main()
{
var p = GetA() ?? GetB();
}
答案 2 :(得分:-1)
运营商的操作数?应该是同一类型:
P a = GetA();
P b = GetB();
P p = a ?? b;