是否有技术原因要求呼叫者使用“out”和“ref”关键字?

时间:2013-04-19 02:42:46

标签: c#

调用带有refout参数的方法时,必须在调用方法时指定相应的关键字。我从样式和代码质量的角度理解(例如,如here所述),但我很好奇是否还需要在调用者中指定关键字。

例如:

static void Main()
{
    int y = 0;
    Increment(ref y); // Is there any technical reason to include ref here?
}

static void Increment(ref int x)
{
    x++;
}

4 个答案:

答案 0 :(得分:12)

我能想到的唯一技术原因是重载决议:你可能有

static void Increment(ref int x)

以及

static void Increment(int x)

This is allowed;如果调用中没有ref,编译器将无法区分它们。

答案 1 :(得分:11)

如果你问的是语言是否可以设计成在呼叫站点不需要,那么答案是肯定的。没有特别的理由他们不能被排除在外。编译器从元数据中获取所需的所有信息,因此可以进行适当的转换。

那就是这样说,这样就不可能有这两个重载:

public void DoSomething(int x);
public void DoSomething(ref int x);

编译器无法消除歧义。

尽管refout可以是可选的,但在这种情况下,允许这些重载。并且编译器可以采用默认值(即非ref),或者发出歧义错误并让你指定你真正想要的那个。

所有这一切,我喜欢必须在呼叫站点指定refout。它告诉我可能会修改参数。在Pascal工作多年,其中var参数的传递方式与传递值参数的方式相同(调用站点的语法相同),我更喜欢C#在这方面的特殊性。

答案 2 :(得分:9)

要求修饰符的另一个原因是将参数更改为refout 更改。如果可以推断ref / out,那么编译新签名的客户端将无法检测到将参数从by-value更改为by-reference的邪恶程序员。如果客户端调用方法

public int Increment(int x)
{
    return x + 1;
}

使用

int result = Increment(x);

假设一个邪恶的开发人员决定更改实现,而是更改引用传递的值,并返回错误代码,如果增量导致溢出:

public int Increment(ref int x)
{
    x = x + 1;
    if(x == int.MinValue)  // overflow
        return -1;
    else 
        return 0;
}

然后,针对签名构建的客户端将不会收到编译错误,但它几乎肯定会破坏调用应用程序。

答案 3 :(得分:-1)

编译器在构建IL时需要知道它正在解释的方法参数。 一个原因是过载如下:

public void (ref int x) {}
public void (int x)     {}

另一个原因是out将明确允许您使用pass-by-value参数使用方法之外的解释值。 ref将提供指向参数的指针,从而将该方法中的任何新值指向相同的内存位置