2017-02-16 64 views
3

我在C# 7.0中查看this code示例,我不確定引擎蓋下的情況以及此循環的性能。使用C#7的foreach聲明中的空合併運算符

foreach (var c in text ?? throw new ArgumentNullException(nameof(text))) 
{ 
    ... 
} 

我的問題:

  1. 是否有條件的聲明得到多次(上 每次迭代)打一次或?
  2. 新的語法看起來不同,這樣做有什麼好處?
+5

當你測試它時,它對性能有什麼影響?你做了測試,不是嗎?請解釋爲什麼你的測試不足以讓你自己理解你的問題的答案。解決你的問題,以便它包含一個很好的[mcve],清楚地顯示你的測試結果,幷包括你對你的測試仍然無法理解的詳細解釋。 –

+2

一次。如果'text'爲空,那麼條件語句被命中一次,這應該是合乎邏輯的,沒有解釋。如果它正在循環,那麼由於枚舉器正在循環中,它也會一次。 –

+0

@PeterDuniho我不確定問題是如何框錯的。 – Svek

回答

2

您應該瞭解foreach內部代碼以瞭解此C#功能。在foreach聲明中表達的右邊部分必須實現IEnumerable(<T>)接口,並且整個循環是,在內部,一個簡單的while,這樣的事情:

// here can be NullReferenceException 
var en = text.GetEnumerator(); 
while(en.MoveNext()) 
{ 
    var c = en.Current; 
    { 
     ... 
    } 
} 

正如你所看到的,有這碼點的NRE能發生,所以你需要檢查枚舉以前整個循環或Enumerable extensions class,像這樣:

if (text.IsNullOrWhitespace()) 
{ 
    throw new ArgumentNullException(nameof(text)); 
} 

// while loop here or text.SomeLinqCodeHere() 

有一些代碼在這裏它是不是真的是不必要的,加入一些熵沒有真正的價值。在有關代碼標準簡單foreach真的意見爲基礎的決策,但這個功能的真正目的的情況下,與其他新事物鏈接它C#7,像?. operator,像這樣:

int? length = customers?.Length ?? throw new ...; 
Customer first = customers?[0] ?? throw new ...; 
int? count = customers?[0]?.Orders?.Count() ?? throw new ...; 

在這種情況下拋出異常類似於代碼行末尾的註釋:

int? length = customers?.Length; // should not be null 
Customer first = customers?[0]; // should not be null 
int? count = customers?[0]?.Orders?.Count(); // should not be null 

但它爲您的代碼添加了一些嚴格的合同規則。

至於foreach循環這樣的表情的表現,前面已經說了,也不會出現因爲獲取枚舉只發生一次,並以前真正的循環。

9

就「foreach工作方式」而言,條件語句只能計算一次。

你可能想了解更多關於如何foreach循環對這些問題的工作:解釋,這是一個新的C#7.0的功能,這將Visual Studio中後釋放
How do foreach loops work in C#?
Does foreach evaluate the array at every iteration?

感謝Svek 2017 RC:
http://structuredsight.com/2016/09/01/c-7-additions-throw-expressions/

我認爲「什麼是好處」是一種基於意見的問題。
在我看來,它沒有帶來任何好處,只是在條款或代碼可讀性方面很難看。
我會建議使用一種廣泛使用的通用性好做法:

if (text == null) // or string.IsNullOrEmpty for strings 
    throw new ArgumentNullException(nameof(text)); 

foreach (var c in text) 
{ 
    // ... 
} 

也許,我們將看到空凝聚+拋出異常使用情況將在幾年內,它會成爲一個新的標準:)

+3

這樣做可能不會更好。原始代碼可能是也可能不是線程安全的,但你的版本不是。你能解釋爲什麼你說這樣更好嗎? – Enigmativity

+3

根據以前的段落,我說「代碼可讀性和流量」更好。檢查在開始或方法中爲空的值並拋出'ArgumentNullException'是一種**常見的良好做法**。這正是所有.NET類,第三方類和所有優秀開發人員所做的。如果每個人都以他們想要的方式開始使用代碼運算符和功能,那麼我們很快就會停止瞭解彼此的代碼。簡碼!=更好。 –

+0

談到線程安全性,我認爲'text'是一個傳遞給函數的參數 - 如果我是對的,那麼這個代碼將**總是**線程安全的。它如果是一個類成員,可以從不同的角度進行修改,那麼還有許多其他技術,方法和功能可以提供線程安全性。使用null-coalescing運算符來拋出新的Exception絕對不是其中之一。 –