Null合并运算符和带有as的强制转换
本文关键字:转换 as 合并 运算符 Null | 更新日期: 2023-09-27 18:24:12
为什么我不能在使用as
的强制转换中使用null合并运算符(??
)?根据我的理解,如果类型不是实例的类型,则使用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
(基本类型)时,我也会收到相同的错误消息。问题似乎与??
运算符有关。
您需要能够在编译时定义test
变量的类型。您试图合并的3个表达式都是不同的类型(d
、c
、b
)。
更具体地说,联合运算符需要两个表达式本质上是相同的类型。每个合并操作都是在操作器的每一侧使用不同类型执行的。要阅读有关此要求的全部详细信息,请查看以下答案:https://stackoverflow.com/a/8898305/674326
您可以将每个表达式强制转换为a
,然后就可以进行编译,因为test
的类型可以确定为a
。但那会破坏你锻炼的目的,不是吗?
var
是一个编译时构造。它不支持动态键入。
因此,你试图做的事情是完全没有意义的。唯一可能的test
类型是a
——你已经有了。
有意义的(合法的)是这样的:
var someValue = (obj as d)?.someProperty ?? (obj as c)?.someOtherProperty;
在这种情况下,没有动态类型——我们只是用不同的方法从两种不同的类型中获得等效值。然而,与使用适当的多态性或至少使用dynamic
相比,即使这样听起来也不是一个好主意。
这与as运算符无关,只是因为编译器无法确定(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
将代码简化为:
var test = (instance as d) ?? (instance as c);
您认为test
的类型是什么?是d
还是c
?只能在编译时确定类型。编译器不会为您隐式地将其转换为相应的基类型。因此,您需要按照@Ksv3n的建议手动执行此操作。