为什么我不能使用空合并运算符(??
)和使用as
的转换?
根据我的理解,使用as
进行投射会产生null
,如果类型不是实例的类型,那么我认为它会尝试表达式的正确部分。
这是我的意思的一个例子:
void Main()
{
a instance = new c();
var test = (instance as d) ?? (instance as c) ?? (instance as b);
}
public class a {}
public class b : a {}
public class c : a {}
public class d : a {}
我得到的错误:
Operator '??' cannot be applied to operands of type 'UserQuery.d' and 'UserQuery.c'
我理解在这种情况下使用var是不合适的,但即使使用dynamic
或a
(基类型),我也会得到相同的错误消息。该问题似乎与??
运算符有关。
答案 0 :(得分:3)
您需要能够在编译时定义test
变量的类型。您尝试合并的3个表达式都是不同的类型(d
,c
,b
)。
更具体地说,合并运算符需要两个表达式基本上是相同的类型。您的每个合并操作都在操作员的每一侧以不同的类型执行。要阅读有关此要求的完整详细信息,请查看以下答案:https://stackoverflow.com/a/8898305/674326
您可以将每个表达式转换为a
,然后您就可以编译,因为test
的类型可以确定为a
。但那会破坏你的练习的目的吗?
答案 1 :(得分:3)
var
是一个编译时构造。它不支持动态输入。
因此,你要做的事情绝对毫无意义。 test
唯一可能的类型是a
- 您已经拥有该类型。
将有意义(并且是合法的)将是这样的:
var someValue = (obj as d)?.someProperty ?? (obj as c)?.someOtherProperty;
在这种情况下,没有动态类型 - 我们只是采用不同的方式从两种不同的类型中获取等效值。然而,与例如相比,即使这听起来也是一个坏主意。使用适当的多态性,或者至少使用dynamic
。
答案 2 :(得分:2)
这与as operator无关,只是因为编译器无法确定(d ?? c)的返回类型。
您可以通过将至少一个操作数强制转换为a
var test = (instance as d) ?? (a) (instance as c) ?? (instance as b);
这是观察此行为的较短样本
c instancec = new c();
d instanced = new d();
a foo = instancec ?? instanced; // Compile error even if we declare foo as a
答案 3 :(得分:0)
稍微简化代码:
var test = (instance as d) ?? (instance as c);
您期望test
的类型是什么?是d
还是c
?该类型必须仅在编译时确定。编译器不会为您隐式地将它强制转换为相应的基类型。所以你需要像@ Ksv3n建议那样手动完成。