C# Null条件运算符和void方法

C# Null条件运算符和void方法,c#,c#-6.0,null-conditional-operator,C#,C# 6.0,Null Conditional Operator,在C#6之前,我会编写代码来处理以下对象: if (_odbcConnection != null) { _odbcConnection.Close(); _odbcConnection.Dispose(); _odbcConnection = null; } 使用6,我可以编写更少的代码: _odbcConnection?.Close(); _odbcConnection?.Dispose(); _odbcConnection = null; 但是这两个是等价的吗?

在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;
这意味着此版本是线程安全的,而第一个版本(带有外部
if
子句)不是。如果某个神秘线程将
\u odbcConnection
设置为
null
If
之后,但在
Close()
Dispose()
之前,将抛出
NullReferenceException

通过使用null条件运算符,可以避免此问题,因为引用首先存储在编译器生成的变量中,然后进行检查和使用


上述转换仅适用于字段和属性。对于局部变量(仅在单个方法的范围内,例如方法参数),这种转换是不必要的,代码最终类似于

if (_odbcConnection != null) _odbcConnection.Dispose();
这是因为本地变量不能由不同的线程更改


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

运行您已经编写的代码,亲自查看。这个翻译是否有文档记录?因为我无法通过查看生成的IL来证明这一点code@SelmanGenç对于局部变量,将不会生成额外的编译器
tmp
,因为任何其他线程都不可能访问局部变量。因此,我的示例翻译只适用于字段或属性。我和dotPeek核对过了。检查反编译的源代码,而不是IL。IL可能会完全忽略这一点,因为它将值加载到寄存器中,因此不再需要额外的变量。它可能会被优化掉。