2011-08-30 48 views
4

這是我想了一會兒現在想的事情。我瀏覽了一系列包含以下錯誤標題的問題,但找不到解釋此案例的問題。另一個「使用未分配的本地變量」無論什麼'「問題

首先看看這個例子:

private void test() { 
    string errorMessage; 
    bool isOK = SomeClassWithBusinessRules.VerifySomeStuff(idOfStuffToVerify, ref errorMessage); 
    if (!isOK) 
     throw new BusinessException(errorMessage ?? "Some error occured."); 
} 

如果您編譯該編譯器將這個消息抱怨:

錯誤2使用未分配的局部變量 '的errorMessage'

將變量初始化器更改爲null將使其消失。

這將編譯:

private void test() { 
    string errorMessage = null; 
    bool isOK = SomeClassWithBusinessRules.VerifySomeStuff(idOfStuffToVerify, ref errorMessage); 
    if (!isOK) 
     throw new BusinessException(errorMessage ?? "Some error occured."); 
} 

那麼,爲什麼我們得到的編譯錯誤?

+0

我認爲'(int idOfStuffToVerify,ref ...)'中的'int'是一個錯字,請更正。 –

+0

確實...已修復,對不起! – Peter

+1

哇,從來沒有一個問題回答如此之快,由兩個頂級SO'ers ...謝謝! – Peter

回答

14

當您將它傳遞給VerifySomeStuff時,您指定的是ref,但它尚未具有值。這是不合法的,因爲VerifySomeStuff可能選擇讀取該值,此時沒有定義的值。分配null滿足明確的分配要求。另一種方法是out

string errorMessage; 
bool isOK = SomeClassWithBusinessRules.VerifySomeStuff(id, out errorMessage); 
if (!isOK) 
    throw new BusinessException(errorMessage ?? "Some error occured."); 

這將是合法的(但需要改變VerifySomeStuff,因爲簽名必須改變,現在是需要退出之前將值分配給參數(如果有異常發生))。從顯示的代碼中,如果沒有錯誤,您可以選擇VerifySomeStuffnull分配給參數。

當然,如果布爾和字符串,然後複製的「是有問題」的宗旨,您還可以使用:

string errorMessage = SomeClassWithBusinessRules.VerifySomeStuff(id); 
bool isOK = errorMessage == null; 
13

您會收到編譯錯誤,因爲用作ref參數的變量必須事先明確分配。如果更改爲使用out參數,而不是方法,這將是罰款:

bool isOK = SomeClass.VerifySomeStuff(id, out errorMessage); 

注意,這需要改變VerifySomeStuff也使它成爲out參數。然後,該方法必須在任何「正常」返回路徑中明確指定一個值 - 以便在該方法正常返回時,明確指定errorMessage

分別參見第10.6.1.2節和第10.6.1.3節的細節refout參數。

6

你被ref傳遞errorMessage。這具有進/出語義。換句話說,協議是收件人可以預期對象已經被初始化,而你沒有這樣做。

看起來好像你只是想要out語義。將VerifySomeStuff更改爲使用out而不是ref代替errorMessage,並且還將呼叫代碼更改爲使用out

請注意,當您通過使用out時,被調用方不允許讀取,直到對象被初始化。被調用者還有責任在返回之前執行該初始化。

5

您還可以通過改變方法糾正「錯誤」來

SomeClassWithBusinessRules.VerifySomeStuff(int idOfStuffToVerify, 
      out string errorMessage); 

當您使用out的負擔轉移到方法,它不會編譯除非你分配到的errorMessage參數。

2

當傳遞ref參數時,被調用代碼可以執行的操作之一是將ref參數變量重新指向新位置,即更新其引用。爲了發生這種情況,變量必須首先指向某個東西,因此必須指定它,即使這只是null

2

你的問題(編譯器爲什麼會抱怨)已經被其他人回答了。我會,不過,建議你重新考慮你的設計:

bool isOK = SomeClassWithBusinessRules.VerifySomeStuff(idOfStuffToVerify, ref errorMessage); 
if (!isOK) 
    throw new BusinessException(errorMessage ?? "Some error occured."); 
} 

由於errorMessage當錯誤發生時,爲什麼還需要額外的返回值時,才需要?您可以縮短這:

string error = SomeClassWithBusinessRules.VerifySomeStuff(idOfStuffToVerify); 
if (error != null) 
    throw new BusinessException(error); 
} 

(當然,那你就沒有「發生一些錯誤」情況了,但顯示「無用」的錯誤消息是不好的做法,反正。)

在事實上,如果錯誤是特殊情況(即東西是不是正規的控制流程的一部分,而是一些指示數據或邏輯錯誤),它可能是有意義的移動異常 VerifySomeStuff:

// no return value 
SomeClassWithBusinessRules.VerifySomeStuff(idOfStuffToVerify); 

class SomeClassWithBusinessRules { 
    void VerifySomeStuff(int id) { 
     ... 
     if (someCondition) 
      throw new BusinessException(error); 
     ... 
    } 
} 
+0

謝謝,這些都是非常有效的論點,我真的很感謝你花時間寫下來!我使用這種方法是因爲該方法產生的錯誤是流程的一部分。當從UI調用這個時,我們向用戶顯示一條消息。如果它在批處理中出錯,我們會拋出一個異常,等等。因爲異常比out/ref變量貴得多,所以這似乎是要走的路。請注意,在我的問題中的案例不是生產代碼的摘錄,錯誤在那裏更加清晰:-) – Peter

+0

@Peter:我明白了,感謝您的澄清。是的,你寫的是有道理的。 – Heinzi

+0

@Peter:你是否考慮過從VerifySoemStuff而不是簡單的bool中返回自己的自定義類型?你可以創建一個既包含成功/失敗布爾,又包含失敗時的錯誤消息的類,以及任何你能想到的東西。然後VerifySoemStuff返回這個類的一個實例。 – Polyfun

相關問題