[英]When is the value of a C# 'out' or 'ref' parameter actually returned to the caller?
當我對out
或ref
參數進行賦值時,是否會立即將值賦給調用者提供的引用,還是在方法返回時分配給引用的out
和ref
參數值? 如果方法拋出異常,則返回值嗎?
例如:
int callerOutValue = 1;
int callerRefValue = 1;
MyMethod(123456, out callerOutValue, ref callerRefValue);
bool MyMethod(int inValue, out int outValue, ref int refValue)
{
outValue = 2;
refValue = 2;
throw new ArgumentException();
// Is callerOutValue 1 or 2?
// Is callerRefValue 1 or 2?
}
由於ref
和out
參數允許方法使用調用者傳入的實際引用,因此在返回控件時,對這些引用的所有更改都會立即反映給調用者。
這意味着在上面的示例中(如果您當然要捕獲ArgumentException
), outValue
和refValue
都將設置為2。
同樣重要的是要注意out
和ref
是IL級別的相同概念 - 只有C#編譯器強制執行out
的額外規則,這要求方法在返回之前設置其值。 因此,從CLR的角度來看, outValue
和refValue
具有相同的語義並且以相同的方式處理。
安德魯是對的; 我只會添加一些額外的細節。
首先,考慮out / ref參數的正確方法是它們是變量的別名 。 也就是說,當你有一個方法M(ref int q)並將其稱為M(ref x)時,q和x是完全相同變量的兩個不同的名稱 。 變量是存儲位置; 你在q中存儲的東西,你也存儲在x中,因為它們是同一位置的兩個不同的名稱。
其次,您所描述的替代方案稱為“復制/復制”引用。 在這個方案中有兩個存儲位置,其中一個的內容在函數調用開始時被復制,並在完成時復制回來。 正如您所注意到的,copy-in-copy-out的語義與拋出異常時別名引用的語義不同。
在這樣奇怪的情況下,它們也有所不同:
void M(ref int q, ref int r)
{
q = 10;
r = 20;
print (q);
}
...
M(ref x, ref x);
在別名中,x,q和r都是相同的存儲位置,因此打印20.在copy-in-copy-out引用中,這將打印10,x的最終值將取決於復制輸出是否從左到右或從右到左。
最后,如果我沒記錯的話,在表達式樹的實現中有一些罕見且奇怪的場景,我們實際上在ref參數上實現了copy-in-copy-out語義。 我應該檢查一下代碼,看看我是否能記住這些場景到底是什么。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.