2010-09-02 185 views
8

1)我知道if…else if語句如何工作,但在下一個示例中,就結果值而言,兩種方法都是相同的。那麼,我使用的兩種方法中的哪一種或者我應該總是選擇一種語義上最接近代碼的方法(這裏我猜這兩種方法在語義上是完全不同的)?那麼你會使用哪種方法,爲什麼?何時使用'if ... else if'以及何時使用

protected string GetNumberDescription(int value) 
{ 
    if (value >= veryBigNumber) 
     return veryBigNumberDescription; 
    else if (value >= bigNumber) 
     return bigNumberDescription; 
    else if (value >= smallNumber) 
     return smallNumberDescription; 
    else 
     return ""; 
} 

protected string GetNumberDescription(int value) 
{ 
    if (value >= veryBigNumber) 
     return veryBigNumberDescription; 
    if (value >= bigNumber) 
     return bigNumberDescription; 
    if (value >= smallNumber) 
     return smallNumberDescription; 
    else 
     return ""; 
} 

2)我注意到的代碼losts書面方式if ... else if報表時採用以下格式:

if ... 
else if ... 
else ... 

但不是(至少在概念上)比較正確的做法:

if ... 
else 
    if ... 
    else ... 
+1

在Java上下文中的類似問題:http://stackoverflow.com/questions/3579918/programming-preference-use-else-ifs-with-multiple-return-statements/ – BalusC 2010-09-02 19:31:47

+1

檢出http://www.refactoring。 com/catalog/replaceNestedConditionalWithGuardClauses.html ... – 2010-09-02 19:32:57

+0

如果有人在由ifs塊處理的內部插入else if語句,則執行第一個操作可能會導致問題。問題是代碼冗餘和性能問題 – Woot4Moo 2010-09-02 19:49:15

回答

16
  1. 您應該使用第一個。它更接受,更合乎邏輯。 (如果這種情況是真的,那麼你以後不關心任何事情......在你的代碼中指明)
  2. 它通常更容易被接受,而且更緊湊和更易讀,可以使用第一種方法(否則如果)。 Python甚至還有一個特定的關鍵字(elif)。
+1

第一個不會保存不必要的評估,因爲每個真實條件都以return語句結束。 – 2010-09-02 19:28:27

+0

@Michael La Voie - 對不起,我剛剛意識到自己的錯誤並糾正了錯誤......我沒有立即注意到 – froadie 2010-09-02 19:29:41

+0

的回覆同意,第二種樣式只是不好的編碼。 – 2010-09-02 19:31:15

7

它們在語義上是相同的。我懷疑在性能上有什麼不同,所以選擇的是風格和可讀性。如果你很好奇,將上面的代碼編譯成一個程序集,並使用Reflector來查看IL中是否有任何區別。我的猜測是,如果有的話,會有一點差異。

+0

我認爲海報意識到生成的代碼將是等效的。他問是否有理由更喜歡一種*編碼風格*。 – Karmastan 2010-09-02 21:11:17

+0

@Karmastan:OP聲明「語義上他們是完全不同的。」它們在語義上不同。我對文體差異並不持有強烈的看法,只是指出它們的意思是一樣的。 – 2010-09-03 13:41:02

11
protected string GetNumberDescription(int value) 
{ 
    string ret = ""; 

    if (value >= veryBigNumber) 
     ret = veryBigNumberDescription; 
    else if (value >= bigNumber) 
     ret = bigNumberDescription; 
    else if (value >= smallNumber) 
     ret = smallNumberDescription; 

    return ret; 
} 

的問題已經回答了,但我說這是因爲:

  1. 有以具有從功能單一的出口優勢。
  2. 重複測試相同的變量,所以if/elseif是最合適的。

編輯補充:

我通常情況下早退出功能像這樣的大風扇:

if (conditionOne) 
{ 
    if (conditionTwo) 
    { 
     if (conditionThree) 
     { 
      interesting_stuff(); 
     } 
    } 
    else 
     boring(); 
} 
return; 

我更高興看到的是:

if (!conditionOne) 
    return; 

if (!conditionTwo) 
{ 
    boring(); 
    return; 
} 

if (!conditionThree) 
    return; 

interesting_stuff(); 
return; 

但是當出現在許多不同的嵌套級別,在閱讀代碼時很容易錯過。

另外,正如在評論中提到的那樣:單​​個出口意味着只有一個地方放置斷點。

+0

你可以擴展你的第一點嗎?我通常會更喜歡其他方式,以使我的代碼更小。 – Karmastan 2010-09-02 21:10:15

+2

由於回報充當控制流量表,使得閱讀代碼更加複雜。如果你有遍歷整個函數體的return語句,那麼當試圖理解函數的工作方式時,你會有更多的使用場景來思考。如果您嘗試修改函數並向其中添加更多代碼,那麼您只能將語句放在方法的開頭,因爲如果您始終希望執行這些語句,因爲如果將它們放在最後,那麼在某些情況下,語句會贏得沒那麼遠。但也許你需要分析結果,所以你不能把它放在一開始。 – AaronLS 2010-09-02 21:36:03

+1

+1我們可以在單次返回檢查結果上放置一個斷點。 – garik 2010-09-03 15:39:02

6

這主要是一個偏好問題。當使用return語句時,我認爲你不需要elses,因爲很明顯,函數在那裏結束。這一切都是非常依賴情況和風格的,所以沒有明確的「最佳」方式來做到這一點。

+0

+1表示情況/風格依賴 - 這是當任何一方都可以接受時,人們爭論的事情。 – 2010-09-02 19:31:50

+0

我同意某種程度。在這種情況下,條件顯然是相互關聯的,其他方式更能防禦bug,所以我傾向於說這不是一個風格問題。 – AaronLS 2010-09-02 19:48:49

4

我會使用第一個選項,因爲它在代碼中顯示比較是「分組」的一些。對於2我認爲他們最終在完全相同的IL代碼。

我總是確保最常見的senario首先在if..else語句中,因爲這對性能最好。

5

我會建議前者,因爲你在四種可能性之間作出了合理的選擇。您將決定分組在if/else if塊中。

如果您將第二個函數中的決定分開,那麼它們看起來根本就沒有連接。顯然,它們是重複的價值變量,但它可能不一定是顯而易見的。

此外,當您無法返回時,請返回空值,而不是空白字符串。在我維護的應用程序中,仍然有必要使用if(value == null || value!=「」)。

+1

string.IsNullOrEmpty(value):-) – Goblin 2010-09-02 19:39:04

+0

哦,我的上帝,我不敢相信我從未想過這個函數會成爲標準庫的一部分。謝謝! – 2010-09-02 19:45:32

13

我個人會用

protected string GetNumberDescription(int value) 
    { 
     if (value >= veryBigNumber) 
      return veryBigNumberDescription; 
     if (value >= bigNumber) 
      return bigNumberDescription; 
     if (value >= smallNumber) 
      return smallNumberDescription; 
     return string.Empty; 
    } 

這真的一切都取決於你的函數是做什麼。如果它像這樣簡單,那麼保持簡單。如果你可能需要做一些結果,然後你將它返回它然後我會使用Egrunin的解決方案

+0

for(Number number:numberCollection)if(value> = number.value)return number.description;拋出新的IllegalArgumentException(); ----這顯然應該是一個存在於你的NumberCollection類中的方法,並且這會變成numberCollection.getDescription(value);不要害怕編碼好。 (我並不是暗示答案對於教學目的來說不是更清楚/更好,只是進行下一步)。另外數字是其中一個單詞,如果您連續輸入太多次,它看起來不正確。 – 2010-09-02 21:00:28

4

1)第一個是更流行的,並在通常的做法。所以堅持標準做法是明智的。

2)通常,當我們有一個以上的條件語句,else if在中間有條件的輸出使用,否則在最後一個條件的輸出使用。此外,它可能更有效,因爲我相信它不必像if-else-if-else ...類型那樣每次檢查相同的條件。

它更像是一個選擇提供給你,你發現你自己走出許多路徑去相同的目的地。但是,您經常聽到或看到的選擇是由於許多用戶和專家的經驗而流行的選擇。

10

如果條件相互排斥,那麼我認爲如果模式是最好的。隨着代碼的發展和變得越來越複雜,意外破解將更加困難,因爲您的控制流更準確地代表了邏輯的互斥性。

考慮一下,如果有人重新分解你的第一個例子是類似egrunin的例子,例如,世界上只有一個返回,但考慮到他們忘了加上「其他」每個若:

protected string GetNumberDescription(int value) 
{ 
    string ret = ""; 

    if (value >= veryBigNumber) 
     ret = veryBigNumberDescription; 
    if (value >= bigNumber) 
     ret = bigNumberDescription; 
    if (value >= smallNumber) 
     ret = smallNumberDescription; 
    // BUG: very big numbers still fall through to this last condition, 
    //   because they meet all conditions 

    return ret; 
} 

他們有隻是引入了一個錯誤。他們可能沒有意識到回報是所表達的邏輯的一部分。雖然這裏的錯誤是顯而易見的,但在現實生活中,這些代碼幾年後可能變得更復雜,更冗長,更難以閱讀,從而更容易犯這樣的錯誤。

檢測意外的錯誤

此外,如果至少一個條件必須得到滿足(即不應該返回一個空字符串),那麼我會拋出一個異常,在最後否則,如果我們假定你是所有的情況下應該處理。這將檢測代碼中的代碼中的錯誤,該代碼在所有elses中都沒有找到匹配條件。如果你沒有拋出異常,那麼這個bug可能會導致奇怪的行爲。剩下的代碼如何處理未初始化的空字符串?主要取決於手頭的代碼。拋出一個異常的想法是在錯誤發生的地方造成一個嚴重錯誤,以便可以很容易地識別和糾正錯誤,而不是讓應用程序繼續以無效返回運行。

if (value >= smallNumber) 
    ret = smallNumberDescription; 
else if(...) 
    ret = otherNumberDescription; 
else 
    throw new InvalidOperationException($"No condition matched for value={value}"); 

return ret; 

如果有適當的異常記錄/通知配對,那麼這將讓你成爲注意到了這個錯誤,並加入到處理意料之外的值的條件。對於非常簡單的條件來說並不是非常必要,但對於主動查找和糾正這類代碼中的錯誤非常有幫助。

+1

這是OP詢問問題的正確答案。 – 2010-09-02 23:19:00

4

這些替代品在語義上非常接近,所以它沒有多大關係。正如在某些答案中所建議的那樣,將結果放入一個字符串變量並在最後返回可能會更好地表示您在該方法中正在執行的操作。

另一種方法是使用條件操作數,它給你一個更簡潔的代碼:

protected string GetNumberDescription(int value) { 
    return 
    value >= veryBigNumber ? veryBigNumberDescription : 
    value >= bigNumber ? bigNumberDescription : 
    value >= smallNumber ? smallNumberDescription : 
    String.Empty; 
} 
+0

我覺得這很難理解。 – 2010-09-06 19:17:27

+0

@Daniel Moura:爲什麼? – Guffa 2010-09-06 20:03:56

+0

我必須考慮理解這段代碼。也許我不習慣看到這種風格。使用if ... else if ... else立即理解,我不必考慮。我使用並看到這樣的代碼a> b? C:D,我認爲沒關係。嵌套條件操作數時,我認爲很難弄清楚發生了什麼。 – 2010-09-08 13:01:04

4

隨着return語句,它其實並不重要。儘管如此,我完全不同意那些說第二個更糟糕的人。是什麼讓它變得更糟?

迴應你的第二個問題:你說得很對。實際上,格式化的兩種方式不僅有效,其中的格式與if/else if相同;他們實際上是字面上的一樣。 C#不實施特定的格式風格,所以這些都是相同的:

// This... 
if (A()) 
    return "Congrats!"; 
else if (B()) 
    return "Not bad!"; 
else if (C()) 
    return "Next time..."; 
else 
    return "Uh-oh."; 

// ...is the same as this... 
if (A()) 
    return "Congrats!"; 
else 
    if (B()) 
     return "Not bad!"; 
    else 
     if (C()) 
      return "Next time..."; 
     else 
      return "Uh-oh."; 

// ...which is the same as this... 
if (A()) return "Congrats!"; else 
         if    (B()) 
      return "Not bad!"; 


else 
{ if 
(C()) 


    return 


"Next time...";else{ 
return "Oh-oh."; 
}} 
4
protected string GetNumberDescription(int value) 
{ 
    return new NumberDescriptor(value).toString(); 
} 

所有你需要的是隱藏自己的邏輯。 不要認爲這太嚴重了,但是......我會那樣做。我知道,您的問題在這裏沒有提供,但是在這個主題中已經有足夠的if/then/else示例。

3

如果函數被認爲返回了四種可能性中的一種,所有這些都被認爲是「成功的」,我會說使用第一種。如果某些回報表示「失敗」,我會使用後一種樣式。例如(例如玩具 - 投擲可能是錯誤的情況下更好):

 
string get_suit_name(int suit) 
{ 
    string suit_names[4] = {"clubs", "diamonds", "hearts", "spades"}; 

    if (0 > suit) /* Avoid LT sign */ 
    return "Suit is improperly negative!"; 
    if (suit >= 4) 
    return "Suit is too big!"; 
    return suit_names[suit]; 
} 
3

那麼從我的角度來看,這將是從最高這些優先級最低。

功能/實現最終目標 降低成本在任何範圍內/水平 可讀性

^^^^請注意,許多對此持有異議我的名單上,並撥打上面的可讀性降低成本,它實際上取決於你的工作環境。和最終目標,但我覺得這是最常見的。但猜猜來自一個沒有多大意義的菜鳥:D

之後,你幾乎是花生。同樣如此? :運營商。如果你確信它更具可讀性,那就去做吧。功能上它並不重要。但是如果(){} else {}與if(){} else有很大不同,那麼if(){}所以選擇最優代碼(最高想要的結果減去意想不到的結果--0.5 *可讀性分數)上。

現在看到代碼對你來說也是一樣的,一個新的屬性會發揮作用,這個代碼會在稍後的階段被編輯嗎?如果是的話,那麼最好去哪?不要忘記代碼的未來,也不要忘記隨意挑選的免費獎金。你甚至可以在兩種情況下都做這兩件事,如果你暫時不能解決它,只是評論另一種,但是這樣做會留下馬虎的文字牆在清理/發佈後被刪除。

3

對於所提供的例子,你不需要擔心「如果」語句,如果你願意犧牲一噸的可讀性,可能一點點速度:

string [] descriptions = {"", smallNumberDescription, bigNumberDescription, veryBigNumberDescription}; 

protected string GetNumberDescription(int value) 
{ 
    int index = Convert.ToInt32(value >= smallNumber) + Convert.ToInt32(value >= bigNumber) 
       + Convert.ToInt32(value >= veryBigNumber); 
    return descriptions[index]; 
} 
3

在性能方面,它們可能是相同的,這取決於編譯器/解釋器。在我看來,第二個更好....更容易調試。

5

您想使用「else if」,因爲只有在第一個「if」不被接受時纔會觸發。在你的情況下,3條if語句沒問題,只是因爲如果後者「if」是正確的,那麼之前的「if」就不可以。

在所有if語句都可以正確的情況下,如果您想使用其他語句。

例如:

if (8<10) { 
return 10; 
} 
if (8<9) { 
return 9; 
} 

這是一個非常簡單的例子,但你的想法。如果只希望觸發一個「if」語句,則使用「else if」。

1

那麼,你的具體情況,我建議這樣的:

protected string GetNumberDescription(int value) { 
    if (value >= veryBigNumber) 
     return veryBigNumberDescription; 
    if (value >= bigNumber) 
     return bigNumberDescription; 
    if (value >= smallNumber) 
     return smallNumberDescription; 

    return ""; 

}

因爲,你從任何真實情況的函數返回時,就沒有必要使用「否則如果'。一般來說,如果兩個條件不是相互排斥的,則使用'else if',但在此情況並非如此。在你的情況下,如果任何條件成立,代碼將不會進一步執行。 另外,最後的'else'不是必需的,因爲只有當上述所有條件都是錯誤的時候,控件纔會到達該點。

這都是你使用它的地方,以及如何。主要動機是儘量提高代碼的可讀性,並儘可能優雅和易於理解。