2010-06-27 37 views
18

據我所知,out參數的唯一用處是調用者可以從單個方法調用中獲取多個返回值。但我們也可以使用ref參數來獲取多個結果值!在什麼情況下'out'參數有用(其中'ref'不能用來代替)?

那麼還有其他的情況,其中out參數可以證明是有用的,我們不能使用ref參數呢?

謝謝。

+0

注:我剛剛發佈[這個答案](http://stackoverflow.com/questions/4102892/real-world-examples-where-c-out-parameters-are-useful/7220754#7220754)一個類似的問題,我描述了一個場景,其中'out'參數對於除返回方法中的多個值之外的其他內容是有用的。 – stakx 2011-08-28 12:04:35

回答

29

是 - refout之間的區別是明確賦值方面:

  • out參數已經被明確地通過方法調用之前調用者分配。它在確實必須明確分配的方法才正常返回(即沒有例外)。然後該變量在呼叫後明確分配給呼叫者

  • A ref參數確實必須由方法調用前的調用方明確指定。它必須在該方法中分配一個不同的值。

因此,假設我們想改變int.TryParse(string, out int)使用ref代替。通常情況下,調用代碼如下所示:

int value; 
if (int.TryParse(text, out value)) 
{ 
    // Use value 
} 
else 
{ 
    // Do something else 
} 

現在,如果我們使用ref,我們不得不調用之前給value一個值,例如:

int value = 0; 
if (int.TryParse(text, ref value)) 
{ 
    // Use value 
} 
else 
{ 
    // Do something else 
} 

顯然,這不是一個巨大差異 - 但它給人錯誤的印象。我們正在分配一個我們無意使用的值,這對可讀性來說並不是好事。 out參數表示值從方法中出來(假設沒有例外),並且您不需要有一個值來開始。

我曾經爲C#5(我不知道它是否會被佔用)的建議之一是,具有out參數的方法應該能夠被視爲返回元組的方法值。與元組更好的支持相結合,這將意味着我們可以做這樣的事情:

var (ok, value) = int.TryParse(text); 

在這種情況下okvalue將分別隱型到boolint。這樣就清楚了方法(text)和即將發佈的內容(兩條信息:okvalue)。

這將根本無法使用,如果int.TryParse使用ref參數,而不是 - 因爲編譯器無法知道是否它會實際上在乎ref參數的初始值。

+0

+1 - 我喜歡out參數隱含的元組結果值的想法。 – Thomas 2010-06-27 19:09:41

+1

@托馬斯:它不是原創的 - 我捏它從F#:) – 2010-06-27 19:32:22

+1

_(有點偏題:)_同意喬恩在他的元組「解包」(whatdoyoucallit)的請求。我仍然不明白爲什麼在.NET/C#4.0中支持元組這麼大驚小怪,而且他們顯然甚至不得不爲CLR調整它 - 同時還留下了非常方便的功能出。 「Tuple」類型看起來非常微不足道,即使幾乎沒有用處。 – stakx 2010-06-27 19:56:24

2

一種out參數是有用的。從技術上講,您可以使用ref參數來實現相同的目標,但out參數在傳達意圖方面做得更好。當你使用ref時,不清楚你爲什麼這樣做,而不是使用out或者代替使用函數結果。據推測,你打算改變通過的價值,但你爲什麼改變它並不簡單從函數簽名中清楚。

8

你可以看一下參數,以這樣的方式

  • 正常參數是參數:
    值可以進入功能通過這樣的參數;因此它必須被初始化。

  • ref參數- 輸出參數:
    值可以進入和離開的函數的通過這樣的參數。由於前者,它也必須被初始化。

  • out參數參數:
    值只應該通過這樣的參數來從函數背面;因此,它不需要被初始化。

我想出了通過研究微軟的COM技術看ref/out參數這種方式。 IDL(接口描述語言)用於描述COM組件接口,使用IDL時,參數將被擴充爲in,outinout聲明符。我懷疑.NET和C#已經部分繼承了COM的這些聲明,儘管名稱略有不同(ref而不是inout)。

對於COM,out參數經常用於檢索接口方法的實際返回值,因爲「實際」返回值通常用於返回HRESULT成功/錯誤代碼。

With。NET,我認爲out參數的重要性要小得多,即使在你想從一個方法返回多個值的情況下(你可能會返回複雜對象或在這些情況下返回Tuple)。

2

我覺得一個很好的例子是int.TryParse()

http://msdn.microsoft.com/en-us/library/f02979c7.aspx

的主要原因是優於裁判是,你並不需要分配一個虛擬值調用之前返回var(甚至隱式)。

所以out告訴你,編譯器:「這個var將在方法中賦值,並且var的初始值,如果有的話,甚至不會被查看。兩者之間

0

主要區別是,如果我們使用裁判那麼我們就調用之前初始化這一點,它是可選的,我們分配我們的方法的價值,我們的裁判變量。

但是,對於方法我們不必明確地初始化它們,但在我們的方法中,我們必須給它分配一些值,否則會產生編譯時錯誤。

相關問題