Null 条件运算符和 void 方法

Null conditional operator and void methods

在 C# 6 之前,我会编写代码来处理像这样的对象:

if (_odbcConnection != null)
{
    _odbcConnection.Close();
    _odbcConnection.Dispose();
    _odbcConnection = null;
}

有了6,我可以写更少的代码:

_odbcConnection?.Close();
_odbcConnection?.Dispose();
_odbcConnection = null;

但这两者是等价的吗?

你下面的两个例子几乎相等。但是第二块

_odbcConnection?.Close();
_odbcConnection?.Dispose();
_odbcConnection = null;

会被编译器翻译成

var tmp1 = _odbcConnection;
if (tmp1 != null) tmp1.Close();
var tmp2 = _odbcConnection;
if (tmp2 != null) tmp2.Dispose();
_odbcConnection = null;

这意味着这个版本是 thread-safe,而第一个(带有外部 if 子句)不是。如果某个神秘线程将 _odbcConnection 设置为 nullif 之后但在 Close()Dispose() 之前,则会抛出一个 NullReferenceException

通过使用 null-conditional-operator 可以避免这个问题,因为引用首先存储在编译器生成的变量中,然后进行检查和使用。


以上翻译仅适用于字段和属性。对于局部变量(仅在单个方法的范围内,例如方法参数),这种翻译是没有必要的,代码最终像

if (_odbcConnection != null) _odbcConnection.Dispose();

那是因为局部变量不能被不同的线程改变。

当然这只是生成的 C#。在 IL 中,您可能不会再看到它,因为它要么被优化掉了,要么已经过时了,因为在 IL 中,参考值被加载到寄存器中,然后进行比较。同样,另一个线程不能再更改寄存器中的值。所以在 IL 级别上,这个讨论有点毫无意义。