2015-09-04 41 views
4

我注意到,C#編譯器(.NET 4.5.2)不允許我編譯下面的代碼:爲什麼out參數需要在try和catch部分內初始化?

public void Test(out string value) 
{ 
    //value = null; 

    try 
    { 
     value = null; 
    } 
    catch (Exception ex) 
    { 
     //value = null; 
    } 
} 

它失敗,出現以下錯誤:

The out parameter 'value' must be assigned to before control leaves the current method

但如果我正在取消catch部分中的作業,它編譯成功。
很明顯,它也編譯我在try聲明之前取消註釋。

所以問題是爲什麼它不足以在try塊中初始化參數out爲什麼我不得不在catch模塊中進行初始化?

+0

此代碼永遠不會失敗,但編譯器在編譯時不檢查它。 –

+1

@ M.kazemAkhgary:你怎麼知道它永遠不會失敗?在'null'可以存儲在變量中之前,必須用'ldnull'將它壓入堆棧。沒有理由不能導致'StackOverflowException'或其他什麼。 –

+0

@DarkFalcon請添加作爲答案 - 所有其他答案只是引用語言規範。我正在尋找一個真正的原因,但想不出一個。 – xxbbcc

回答

1

編譯器沒有足夠的智能來理解try-block中的代碼可能包含多個部分,不會失敗的部分以及可能會失敗的部分。

你已經初始化的試塊內out參數事實是根本不夠的編譯器,在try塊裏的任何東西可能根本不會發生,因此out參數可能尚未給予該方法返回之前的值,因此您會得到該錯誤。

當您將初始化添加到catch-block時,您基本上會說(根據編譯器的理解),我明白try-block中的代碼可能沒有完全執行或完全執行,所以請確保在繼續之前完成此操作。

+1

不,編譯器*確實*有足夠的智能知道try塊*可以*在任何時候失敗,甚至在它可以分配之前。假設try塊*必須分配值,這將是* invalid *。 – Servy

6

原因是因爲out關鍵字保證該參數將在方法退出之前分配給該參數。因此,如果在value = null;行執行之前引發異常,並且在catch塊中沒有對該參數的分配,則該保證被破壞。

如果您有一個if else語句,其中兩個邏輯塊之一沒有執行任務,那麼它們應該是相同的。

正如注意到the MSDNoutref很相似,分配到該參數將開展自己的方法的製造,但ref不作此相同的保證。因此,如果期望的結果是try catch,其中catch塊中沒有分配,則可能需要ref關鍵字。

此外,如果這個任務是要在try塊執行的最後一行,你可以在邏輯上它移動到finally塊,這保證了一個異常的try拋出,因此它會執行,滿足out的要求。

+0

起初,我想寫一些類似的東西,但是'if..else'與初始化變量明顯不同,就像'try'中的第一個實際語句。如果'try'沒有執行,甚至不能保證'catch'將會執行。 – xxbbcc

+0

@xxbbcc在這種情況下程序將停止工作!所以沒有更多的步驟 –

+0

@ M.kazemAkhgary是的。這不會阻止編譯器瞭解該變量已在'try'塊中初始化。 – xxbbcc

3

必須在函數體中設置out參數。由於try塊中的代碼可能執行也可能不執行(因爲可能會拋出錯誤並將控制權移交給錯誤處理程序),所以在離開函數之前,必須在某處設置變量。在catch塊是一個有效的地方,是前/ try { ... } catch{ ... }後,或在finally { ... }

3

根據C#規格說明,它說

All output parameters of a function member must be definitely assigned at each location where the function member returns (through a return statement or through execution reaching the end of the function member body). This ensures that function members do not return undefined values in output parameters, thus enabling the compiler to consider a function member invocation that takes a variable as an output parameter equivalent to an assignment to the variable.

try..catch情況下,函數既可以從返回嘗試或從趕上。因此,如果output parameters已在兩個執行路徑中分配了一個值,則每個規範編譯器都會編譯時間檢查,因此有兩個執行路徑。

解決您的問題的方法是將默認值分配給out parameter。稍後,您可以用適當的值在Try中初始化它,編譯器不會打擾您。