C# 运算符'';无法应用于子类类型的操作数
以下代码给出了主函数第二行标题中的错误C# 运算符'';无法应用于子类类型的操作数,c#,casting,language-design,C#,Casting,Language Design,以下代码给出了主函数第二行标题中的错误 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()??Get
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();
工作
我很好奇,为什么编译器不明白这两个类都是左侧容器的子类,并且允许在没有强制转换的情况下进行操作?左侧参数的类型必须与右侧的类型兼容,反之亦然。换句话说,必须存在从
B
到A
或从A
到B
的隐式转换
var a = x ?? y;
在上面,如果存在从y
到x
的隐式转换,则x
的类型将成为表达式的类型。如果没有从y
到x
的隐式转换,但是有从x
到y
的隐式转换,则y
的类型将成为表达式的类型。如果两个方向均不存在转换,动臂;编译错误。根据规范:
表达式的类型a??b取决于操作数类型之间可用的隐式转换。按照优先顺序,a的类型为??b是A0、A或b,其中A是A的类型,b是b的类型(前提是b有一个类型),如果A是可空类型,A0是A的基础类型,或者A是其他类型。具体来说,a??b处理如下:
•如果不是可空类型或引用类型,则会发生编译时错误
•如果A为可空类型,且存在从b到A0的隐式转换,则结果类型为A0。在运行时,将首先计算。如果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不兼容,并发生编译时错误
运算符的操作数??应为同一类型:
P a = GetA();
P b = GetB();
P p = a ?? b;
我很好奇,为什么编译器不明白这两个类都是左侧容器的子类,并且允许不使用强制转换的操作
因为这样做是允许的:
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();
}
它们不必是相同的类型,只需存在从一个到另一个的隐式转换。啊,我明白了,我正在写一个非常复杂的注释,当我重新阅读你的示例时,意识到LHS的类型是从RHS上表达式的计算中派生出来的。起初,我认为只要
x
和y
都能转换成a
,那就好了!是的,包括被分配的变量的类型是最直接的方法,也是我最初认为的工作方式。我很想听听像埃里克·利珀特这样的人对这件事的看法,以及为什么它是这样设计的。。。但是坚持住<代码>变量p=(对象)GetA()??GetB()代码>是允许的。它可能在语法上不同,但达到了相同的逻辑目的。@乔:您可以将任何内容强制转换为object,并且由于存在从B到object的隐式转换,因此结果表达式将返回object。在这里使用var会伤害示例,因为如果您执行强制转换,p将是object类型。@Ed,我真的不明白您的意思。如果我希望p可以是SqlConnection或Random,那么上面的代码是合法的。但是,??
运算符的语法/规则阻止我这样做。基本上,我想我是说,如果我认为p是一个对象是可以的,那么这个例子并没有说明为什么它不能。。。因为一个简单的演员给了我想要的,但却没有给你想要的;返回类型将是object。您必须执行另一个强制转换才能获得可以使用的特定类型。在最初的示例中,理想情况下,父对象将具有两个子对象的公共属性,因此我不在乎哪个属性不为null,只要其中一个为null,所以我可以执行p.CommonVariable。所以在我的场景中,它确实让我得到了我想要的,并且类型转换它只是一个“变通方法”?