NET|Ref 和out 的區別和聯絡

weixin_34050427發表於2017-12-19

首先看一下msdn上是怎麼描述的。

Therefkeyword causes an argument to be passed byreference, not by value. The effect of passing by reference is that any changeto the parameter in the called method is reflected in the calling method. Forexample, if the caller passes a local variable expression or an array elementaccess expression, and the called method replaces the object to which the refparameter refers, then the caller’s local variable or the array element nowrefer to the new object.

我嘗試翻譯一下。ref關鍵字是引用傳遞,區別於按值傳遞。引用傳遞的作用是,呼叫方法中的對引數的任何更改,在函式執行完成後都會影響到該引數。例如,如果呼叫方傳遞一個區域性變數表示式或陣列元素訪問表示式,呼叫的方法將替換引用引數指向的物件,則呼叫方的本地變數或陣列元素將引用新物件。

Theoutkeyword causes arguments to be passed byreference. It is like therefkeyword,except thatrefrequires that the variable be initializedbefore it is passed. To use anoutparameter, both the method definition and thecalling method must explicitly use theoutkeyword. For example:

out關鍵字也是引用傳遞引數。它就像REF關鍵字,除了REF要求變數在它被傳遞之前被初始化。若要使用out引數,方法定義和呼叫方法必須顯式使用out關鍵字。

簡單概括,在功能作用上,ref和out都是引用傳遞,實現的功能,官方的說法是為了保留函式執行過程中對變數的改變能夠得以保留。我的個人理解是為了解決多個返回值的情況。但一個的基本的共識是這兩個關鍵字是基本可以相互替代的。那麼為什麼還有這兩種關鍵字還會同時存在呢。下面我們來簡單分析一下。

用一個簡單的例子來實驗一下。我們需要在一個函式中完成兩個變數x和y的求和和求差

6395583-69845a82d901ad27.png

首先我們來看一下,a和b作為普通引數傳遞,此時,函式執行完成後,a和b的值仍舊是0,函式內部對他的賦值丟失了。

6395583-1b27ecda5fb51c48.png

然後我們使用ref關鍵字來試一下,會發現使用ref關鍵字的時候,我們在函式內部對他的賦值,在函式執行完成後並未丟失

同樣的,使用out關鍵字的之後,函式內部的結果在函式執行完成後,仍得以保留。

6395583-a8e17e00e690c742.png
out關鍵字


6395583-36e3eff1a11931ad.png
ref關鍵字

以上不難看出,ref和out關鍵字都實現了引用傳遞,完成了多個返回的功能。

我們把對a和b的賦值去掉,就可以看到差別了。

6395583-4dd0b4f869cd446a.png
out模式下去掉變數初始化
6395583-2d412d3547dcc008.png
ref模式下去掉初始化
6395583-cafdb29cc56b2f77.png
不使用關鍵字 去掉變數初始化

去掉a和b的賦值,對out是沒影響的。Ref和普通傳值都出出現使用未賦值變數的報錯。

普通傳值很好理解,變數在使用前必須初始化。而ref的第一要素也是使用前必須初始化,而out是不需要的。

然後我們來解決第二個問題,既生瑜何生亮,既有ref何生out,看什麼時候ref和out在那些情況下不能互換。

需求是動態的,問題也是,剛才的問題我們稍微改變一下。

需要在函式N中實現,x>y求和求差

6395583-097eea38304b5ed1.png
x>y 使用ref out求值

對比上圖,我們會發現,我們加了if條件,改造函式之後,out編譯不過了。

原因就在於out關鍵字的變數在使用前可能沒有初始化,要求必須在函式內部被賦值。也就是條件分支必須完全覆蓋。剛才那個地方,我們稍微改造一下即可。

6395583-0e3f3d5459894550.png
out模式下增加賦值分值

以下這段話,純屬個人理解,ref傾向於傳遞,而out傾向於返回,因此無論是傳遞還是返回,過程中被改變,結果也會被改變。區別在於,傳遞的過程可能被改變也可以不被改變,而返回是必須返回一個固定的值。如果比較難懂,可忽略此段。

我們再來模擬一個問題

現有變數x,y,a,b,如果x>y則a+1,b-1反之b+1,a-1。我們會發現out很難寫。而如果存在多組x,y的情況,out更是無法實現。

那麼out的常用使用場景有哪些呢。我用的最多就是系統函式TryParse。我們定義了一個變數,無論使用convert還是parse都有可能會報錯,但tryparse在內部處理了這個問題。即使轉換異常,函式也會在內部幫我們把變數初始化成固定值。

相關文章