2017-02-07 35 views
1

C#6之前,我会写代码来处理类似的对象:空条件运算符和无效的方法

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

随着6,我可以写更少的代码:

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

不过是两个相当于?

+3

运行您已经编写并自行查看的代码。 – Servy

回答

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条款)则不是。如果某个神秘线程会在if之后但在Close()Dispose()之前将_odbcConnection设置为null,则会抛出NullReferenceException

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


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

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

这是因为局部变量不能由不同的线程来改变。

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

+0

这个翻译记录在某处?因为我无法通过查看为本地变量生成的IL代码 –

+0

@SelmanGenç来证明它,所以不会有额外的编译器生成'tmp',因为任何其他线程都不可能访问局部变量。所以我的示例翻译仅适用于字段或属性。我用dotPeek检查了它。检查_decompiled sources_,而不是IL。 IL可能完全忽略它,因为它将值加载到寄存器中,因此不再需要额外的变量。它可能会被优化掉。 –