14

out当我对or参数进行赋值时ref,是立即将值分配给调用者提供的引用,还是在方法返回时将outandref参数值分配给引用?如果方法抛出异常,是否返回值?

例如:

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?
}
4

2 回答 2

26

由于refout参数允许方法使用调用者传入的实际引用,因此在返回控制权时,对这些引用的所有更改都会立即反映给调用者。

这意味着在您上面的示例中(如果您要抓住ArgumentException当然),outValue并且refValue都将设置为 2。

同样重要的是要注意,out它们ref在 IL 级别是相同的概念 - 只有 C# 编译器强制执行额外规则,因为out它要求方法在返回之前设置其值。因此,从 CLR 的角度来看outValuerefValue它们具有相同的语义并且被以相同的方式对待。

于 2010-01-07T23:26:17.363 回答
14

安德鲁是正确的;我只会添加一些额外的细节。

首先,考虑 out/ref 参数的正确方法是它们是variables 的别名。也就是说,当您有一个方法 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 语义,这种情况很少见且很奇怪。我应该查看该代码,看看我是否能记住这些场景到底是什么。

于 2010-01-08T16:45:53.733 回答