在C#6之前,我会编写代码来处理像:
这样的对象if (_odbcConnection != null)
{
_odbcConnection.Close();
_odbcConnection.Dispose();
_odbcConnection = null;
}
使用6我可以编写更少的代码:
_odbcConnection?.Close();
_odbcConnection?.Dispose();
_odbcConnection = null;
但两者是否相同?
答案 0 :(得分:6)
你的两个较低的例子几乎相等。但第二块
_odbcConnection?.Close();
_odbcConnection?.Dispose();
_odbcConnection = null;
将由编译器翻译为类似
的内容var tmp1 = _odbcConnection;
if (tmp1 != null) tmp1.Close();
var tmp2 = _odbcConnection;
if (tmp2 != null) tmp2.Dispose();
_odbcConnection = null;
这意味着此版本是线程安全的,而第一个版本(使用外部if
子句)则不是。如果某个神秘线程在_odbcConnection
之后null
或if
之后将Close()
设置为Dispose()
,则会抛出NullReferenceException
。
通过使用null-conditional-operator可以避免这个问题,因为引用首先存储在编译器生成的变量中,然后进行检查和使用。
以上翻译仅适用于字段和属性。对于局部变量(仅在单个方法的范围内,例如方法参数),此翻译不是必需的,代码最终会像
一样if (_odbcConnection != null) _odbcConnection.Dispose();
这是因为不同的线程无法更改局部变量。
当然这只是生成的C#。在IL中,您可能不会再看到它,因为它被优化掉或过时,因为在IL中,参考值被加载到寄存器中然后进行比较。同样,另一个线程不能再在寄存器中更改该值。所以在IL级别上,这种讨论有点毫无意义。