2010-09-02 33 views
13

我只是好奇,爲什麼這個代碼...開關+枚舉=並非所有的代碼路徑返回一個值

enum Tile { Empty, White, Black }; 
    private string TileToString(Tile t) 
    { 
     switch (t) 
     { 
      case Tile.Empty: 
       return "."; 
      case Tile.White: 
       return "W"; 
      case Tile.Black: 
       return "B"; 
     } 
    } 

拋出這個錯誤。 t不可能承擔任何其他價值,是嗎?編譯器是否應該足夠聰明來解決這個問題?

回答

29

不,您可以使用任何int值轉換爲Tile。試試這個:

Tile t = (Tile) 5; 
string s = TileToString(t); 

枚舉是數字,有效地將一組名稱......但無論是編譯器和CLR強制執行的枚舉類型的值都有一個名字。這是一個痛苦,但它是...

我會建議一個默認情況下拋出ArgumentException(或可能ArgumentOutOfRangeException)。

+4

由於該方法是私有的,因此,主叫方應通過唯一的好東西(因爲呼叫者的作者是*您*,而不是你的用戶)我會建議一個Debug.Fail(「Bad caller!沒有餅乾!」)或類似的默認情況。 – 2010-09-02 14:43:15

+5

@Eric:可能...除非你仍然需要返回一些東西或拋出異常*以滿足可達性要求。就我個人而言,我從來沒有像'調試。*'的風扇 - 我傾向於在發佈模式下看到與調試模式相同的異常,但這可能只是我。 – 2010-09-02 14:54:12

0
switch (t) 
{ 
    case Tile.Empty: 
     return "."; 
    case Tile.White: 
     return "W"; 
    case Tile.Black: 
     return "B"; 
    default: throw new NotSupportedException(); 
} 

正如喬恩指出的那樣,這個值是不可或缺的 - 一個枚舉可以從任何整數值中轉換出來。你只需要處理默認值。

1

這是因爲如果你的t值不匹配任何開關的情況下,它將會掉出開關,因此你的方法不會返回一個值。但是,您已經聲明它會返回一個字符串。您需要添加默認到交換機,或返回NULL:

enum Tile { Empty, White, Black }; 
    private string TileToString(Tile t) 
    { 
     switch (t) 
     { 
      case Tile.Empty: 
       return "."; 
      case Tile.White: 
       return "W"; 
      case Tile.Black: 
       return "B"; 
     } 
     return null; 
    } 
+0

「......如果你的t值不符合任何開關情況......」 - 這正是我的問題。 *如何*它不能匹配任何開關情況? – mpen 2010-09-02 08:24:01

+0

因爲,正如Jon所說,Enum實際上只是一個整數的表示。既然你可以投一個整數到Tile枚舉,那麼你可以在技術上傳遞一個無效的參數。 – BeRecursive 2010-09-02 09:11:47

1

添加默認情況下:

enum Tile { Empty, White, Black }; 
    private string TileToString(Tile t) 
    { 
     switch (t) 
     { 
      case Tile.Empty: 
       return "."; 
      case Tile.White: 
       return "W"; 
      case Tile.Black: 
       return "B"; 
      default: 
       return "."; 
     } 
    } 
+0

我知道解決方案,只是想了解*爲什麼*這是必要的。 – mpen 2010-09-02 08:25:15

+2

枚舉可以隨時用新值進行擴展。因此,您需要使用默認情況來進行陷阱,否則最終的代碼不會涵蓋所有可能的情況。 – Bart 2010-09-02 08:28:10

22

喬恩當然是完全正確的,枚舉可以有它潛在的任何值類型,因此該開關並不詳盡,因此存在不返回的代碼路徑。 但是,這不是一個完整的問題分析。 即使是交換機是徹底的情況下,你仍然會得到錯誤。

試試:

int M(bool b) 
{ 
    switch(b) 
    { 
     case true : return 123; 
     case false: return 456; 
    } 
} 

或者

int M(byte b) 
{ 
    switch(b) 
    { 
     case 0: case 1: case 2: ... all of them ... case 255: return 123; 
    } 
} 

在這兩種情況下,你會得到相同的 「在非void方法到達終點」 的錯誤。

這只是C#規範的「可達性檢查」部分中的一個疏漏。我們將switch語句的結束點定義爲可訪問,如果它沒有缺省段,句點。對於開關來說,沒有特別的安排可以徹底消耗其輸入的每個可能的值。這是語言設計師錯過的一個角落案例,而解決這個問題從來沒有達到過高的優先級。

有關switch語句的分析,其他三個有趣的事實,請參閱:

http://ericlippert.com/2009/08/13/four-switch-oddities/

+0

噢,該死的,我想現在就給你們兩張支票。哈哈......這很公平。我想這是真正的原因! – mpen 2010-09-02 17:25:48

相關問題