2012-02-23 111 views
8

好吧,考慮下面的代碼:編譯時錯誤和無法訪問的代碼

private const int THRESHHOLD = 2; 

static void Main(string[] args) 
{ 
    string hello; 

    if (THRESHHOLD > 1) return; 
    Console.WriteLine(hello);   
} 

令人驚奇的是這個代碼不拋出一個「使用未分配的局部變量的‘你好’」編譯時錯誤。它只是給出了一個警告「無法到達的代碼檢測」。

即使代碼無法訪問,仍然是編譯時錯誤,我認爲正確的做法是拋出編譯時錯誤。如果我要做到以下幾點:

private const int THRESHHOLD = 2; 

static void Main(string[] args) 
{ 
    string hello; 

    if (THRESHHOLD > 1) return; 
    hello.LMFAO();  
} 

果然,我得到一個「‘串’不包含‘LMFAO’,沒有擴展方法‘LMFAO’接受一個類型的第一個參數的定義「字符串'可以找到(你是否缺少使用指令或程序集引用?)「編譯時錯誤。

爲什麼與使用未分配的變量不一樣?

編輯更改const變量,因此它更少分散注意力。我認爲很多人都忽略了這個問題的重點,這取決於哪種情況,編譯時錯誤優先於不可訪問的代碼。

+6

只是想知道:你曾經想TRUE;以評估什麼,但'真'? – 2012-02-23 16:07:31

+2

未使用的變量不會阻止您的代碼工作或編譯,這就是爲什麼它只是一條警告消息。試圖使用未定義的方法會阻止你的代碼運行,所以是一個錯誤。我不確定我是否理解這個問題。 – AaronS 2012-02-23 16:09:01

+0

@BrianRasmussen也許他是來自'真'關鍵字全部大寫的語言? – Servy 2012-02-23 16:10:59

回答

12

詹姆斯·邁克爾·黑爾的回答給出了法律上解釋:局部變量明確賦值,因爲代碼是不可達到的所有局部變量的可達代碼明確賦值。換句話說:如果有一種方法,程序只有一個錯誤觀察未初始化的局部變量的狀態。在你的程序中沒有辦法觀察本地,因此它不是一個錯誤。

現在,我注意到,爲無限聰明的編譯器是不需要的。例如:

void M() 
{ 
    int x = 0; 
    int y; 
    if (x + 0 == x) return; 
    Console.WriteLine(y); 
} 

你知道,我知道,該方法的最後一行是不可達的,但是編譯器不知道,因爲可達性分析不知道,零是整數的添加劑身份。編譯器認爲最後一行可能是可訪問的,因此會給出錯誤。

有關設計的編程語言可達性和明確賦值分析儀方面的更多信息,請參閱我的主題文章:

http://blogs.msdn.com/b/ericlippert/archive/tags/reachability/

http://blogs.msdn.com/b/ericlippert/archive/tags/definite+assignment/

我注意到,雖然,沒有人回答更深的問題,這是爲什麼應該在不可達代碼中抑制錯誤?如您所見,我們在無法訪問的代碼中提供其他語義分析錯誤。

考慮到決策的利弊,你要想想爲什麼會有人有無法訪問的代碼在首位。要麼它故意無法到達,要麼無意無法到達。

如果是無意可達那麼程序包含一個錯誤。警告已經提醒人們注意主要問題:代碼無法訪問。如果存在不可達代碼,則有嚴重錯誤控制流程。很可能,開發人員必須對該方法的控制流程進行重大改變;我們對無法訪問的代碼所做的任何局部變量分析都可能是誤導性的噪音。讓開發人員修復代碼以便一切都可以到達,然後然後我們將分析控制流相關錯誤的現在可達的代碼。

如果無法訪問的代碼是不可訪問,因爲開發商它是不可到達的,那麼賠率是很好的,他們都在做這樣的事情:

// If we can Blah, then Frob. However, if we cannot Blah and we can Baz, then Foo. 
void M() 
{ 
    int y; 
    // TODO: The Blah method has a bug and always throws right now; fix it later. 
    if (false /* Blah(out y) */) 
    { 
     Frob(y); 
    } 
    else if (Baz(out y)) 
    { 
     Foo(y); 
    } 
} 

應該Frob(y)錯誤這個項目?

+1

好東西一如既往。感謝Eric的回答,以及你爲什麼實施的行爲是理想的例子使得它更清晰。 – InBetween 2012-02-23 19:46:34

1

當編譯器發現代碼不可訪問時,它不會爲它生成代碼 - 因此不存在問題。

如果您將return行取出,則最後一行變爲可再次訪問,編譯器將爲其生成代碼,並且會告訴您存在問題。

12

如果您在C# language specification在第5的樣子,它指出:

對於最初未分配的變量中絕對算得 在某個位置分配,必須 發生在每一個賦值給變量可能的執行路徑通往該位置。

並進一步在5.3.3.1:

v在任何無法訪問的語句開頭明確賦值。

由於不可達的代碼不是可能的執行路徑,因此不需要指定它來避免錯誤。

至於你的問題,爲什麼一個未知函數是不可達代碼中的編譯器錯誤,而未賦值的變量不是。你必須考慮上面的標準。無法訪問的代碼並不意味着它不能在語法上有效。代碼仍然必須是可編譯的,唯一的區別是無法訪問的代碼會使它認爲所有初始未分配的變量都在此時分配。但這並不意味着你可以注入一些像未定義的變量或方法那樣的語法無效的東西。

未分配變量的錯誤消息也給了我們一個提示,它告訴我們一個最初未分配的變量必須在使用前分配,但由於代碼無法訪問,所以在技術上並未使用...

+0

是的,行爲是根據規範。我更感興趣的是爲什麼可達性優先於明確的分配。埃裏克的例子顯示了一個你希望它如此的情況。感謝你的回答。 – InBetween 2012-02-23 19:50:02

+0

@InBetween:不用擔心,他是上師:-) – 2012-02-23 19:52:41