空值传播运算符

6

我稍微查了一下,但没有找到关于新的C# 6.0编译器如何分解新的空值传播命令的答案,例如以下内容:

BaseType myObj = new DerivedType();
string myString = (myObj as DerivedType)?.DerivedSpecificProperty;

我想知道的是它如何处理这个问题。
它是否将as转换为新的DerivedType变量进行缓存(即,这只是as转换后紧接着一个null比较的语法糖),还是实际执行as转换,检查是否为空,然后如果不为空,重新转换并继续执行。
1个回答

9

它会将as转换为一个新的DerivedType变量进行缓存(也就是说,这只是as转换后跟null比较的语法糖)。

是的。

你的代码将被编译成类似于以下内容:

BaseType myObj = new DerivedType();
DerivedType temp = myObj as DerivedType;
string myString = temp != null ? temp.DerivedSpecificProperty : null;

你可以在这个TryRoslyn示例中看到(尽管,正如hvd所评论的那样,通过查看IL,你可以看到实际上没有DerivedType变量。引用只是存储在堆栈上)。

在 IL 中,无法声明 DerivedType 或 BaseType 的变量。在 C# 中,给定这些类型的变量,它们的 IL 表示将是 object。这就是为什么转换是 dup 的原因。在 IL 中,引用从一开始就不是 BaseType 引用。 - phoog
@hvd,我认为重点不在于实例是存储在变量中还是存储在堆栈上,而在于是否有“as”和空值检查,或者是否有重新转换。 - i3arnon
@i3arnon 这很公平。我认为值得指出的是,它并不完全像 OP 所建议的那样工作,但确实非常接近。 - user743382
@hvd 我同意。我添加了一条注释。 - i3arnon
1
@hvd 不用在意。我有点困惑。但你也是:dup不代表转换,它是由于需要在堆栈上有两个派生引用实例而产生的。第一个实例用于与null比较;比较会弹出堆栈上的两个值,因此需要第二个实例来调用属性getter。转换通过isinst实现,它将对象从堆栈顶部弹出,然后根据参数是否可以分配给给定类型将对象或null重新推回堆栈。(堆栈上的引用仅具有一个类型:O。) - phoog
显示剩余11条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接