2017-02-07 36 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可能完全忽略它,因爲它將值加載到寄存器中,因此不再需要額外的變量。它可能會被優化掉。 –