Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/grails/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 运算符'';无法应用于子类类型的操作数_C#_Casting_Language Design - Fatal编程技术网

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。所以在我的场景中,它确实让我得到了我想要的,并且类型转换它只是一个“变通方法”?