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是不合适的,但即使在使用dynamica(基本类型)时,我也会收到相同的错误消息。问题似乎与??运算符有关。

Null合并运算符和带有as的强制转换

您需要能够在编译时定义test变量的类型。您试图合并的3个表达式都是不同的类型(dcb)。

更具体地说,联合运算符需要两个表达式本质上是相同的类型。每个合并操作都是在操作器的每一侧使用不同类型执行的。要阅读有关此要求的全部详细信息,请查看以下答案: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的建议手动执行此操作。