8

重复:调用者的“out”关键字的目的是什么?

为什么我需要在声明和调用中都使用'ref'关键字。

void foo(ref int i)
{

}

例如,考虑上述功能。如果我在没有 ref 关键字的情况下调用它

foo(k);

它会给我错误:

参数 '1' 必须与 'ref' 关键字一起传递

为什么仅在方法签名中指定还不够?

4

6 回答 6

15

这是因为ref表示参数应该通过引用传入。它类似于 C++ 中的指针

例如;

void CalFoo()
{
  var i=10;
  foo(ref i);  //i=11
}
void foo(ref int i)
{
   i++;
}

void CalFoo()
{
  var i=10;
  foo(i);  //i=10
}
void foo(int i)
{
   i++;
}

我认为您可以在一个班级中foo(ref int)同时拥有两者。foo(int)因此,如果您不指定ref.. 编译器如何知道要调用哪一个?

于 2009-10-06T07:31:37.267 回答
9

它增强了可读性/可理解性:当您查看方法调用时,您知道 ref 值可能会更改。

于 2009-10-06T07:33:35.263 回答
4

(如前所述,这是这个问题的骗局。)

一方面,它被用作方法重载的一部分:

public void Foo(string x) { ... }
public void Foo(ref string x) { ... }

...

string x = "";
Foo(x); // Which should be used if you didn't have to specify ref?

现在一个答案可能是禁止这种重载......但我认为 C# 要求调用方将其作为文档是一件好事:

  • 当您使用ref(或out)时,行为会发生显着变化
  • 通过调用 ref/out 的罕见用法,这意味着您永远不需要检查参数是按值传递还是按引用传递
  • 它还会影响您可以传递的内容(例如,您不能传递文字或方法调用的结果)。当它明确时,这会更清楚。

请注意,C# 4 确实允许隐式使用reffor COM 方法,因为有很多ref参数实际上并没有行为ref或者至少,它们没有利用它)。在这种情况下,编译器会引入一个新的局部变量,以便从调用者的角度来看,参数实际上按值传递的:

ComMethod(x);

翻译成:

MyType tmp = x;
ComMethod (ref tmp);

这是对 COM 方法的一个很好的折衷方案,但我很高兴普通托管代码并非如此。

于 2009-10-06T07:41:33.267 回答
3

由于方法和调用者可能彼此“远离”(不同的程序集,您甚至可能没有包含该方法的程序集的来源),因此必须明确指定 out 和 ref 有助于明确意图。所以这对用户来说是一件让他们真正知道自己在做什么的东西,而不是技术上的必需品。

于 2009-10-06T07:34:46.040 回答
3

虽然ref大部分时间可以从方法签名中推断出来,但它始终是强制性的,因为它可以在方法调用后完全改变代码的行为。考虑:

string hello = "world";
MyMethod(ref hello);
Console.WriteLine(hello);

如果没有ref关键字,您总是希望代码打印出“世界”,而实际上,它可以打印任何内容。

于 2009-10-06T07:35:01.733 回答
1

我还听说(或在某处读到——也许是在与语言设计师的一次采访中)原因(就像 C# 中的许多其他“功能”一样)是为了提醒程序员他要调用的函数使用参数引用。

于 2009-10-06T07:42:37.603 回答