为什么ref和out不足以消除C#中重载的歧义?

为什么ref和out不足以消除C#中重载的歧义?,c#,.net,methods,C#,.net,Methods,例如,为什么此方法Max(ref int x,ref int y)不被认为是Max(int x,int y)的过载?为什么与out相同?语言设计者决定以这种方式创建它 我怀疑(这只是我的观点)这是因为必须指定ref和out以减少混淆。该语言可以很容易地设计为不需要显式指定ref/out,并让编译器隐式地执行,但这会导致混淆。类似地,使这些重载会阻止其他语言以这种方式编写(因为CLR不仅仅是C#),并且会增加许多用户的总体困惑,而且调用哪个方法也不太清楚。ref和out是同一回事,象征性地说。CL

例如,为什么此方法
Max(ref int x,ref int y)
不被认为是
Max(int x,int y)
的过载?为什么与out相同?

语言设计者决定以这种方式创建它


我怀疑(这只是我的观点)这是因为必须指定
ref
out
以减少混淆。该语言可以很容易地设计为不需要显式指定
ref
/
out
,并让编译器隐式地执行,但这会导致混淆。类似地,使这些重载会阻止其他语言以这种方式编写(因为CLR不仅仅是C#),并且会增加许多用户的总体困惑,而且调用哪个方法也不太清楚。

ref
out
是同一回事,象征性地说。CLR不区分这两者。C#语言正在做出区分。对于CLR,只有
ref

这个问题假设了一个错误的前提

 Max(int x, int y)
 Max(ref int x, ref int y) 
 Max(out int x, out int y)
是名为
Max
的方法的所有重载。但是,请注意,在任何给定的类定义中,只能出现最后两个中的一个。根据规范§3.6:

方法的签名由方法的名称、类型参数的数量以及每个形式参数的类型和种类(值、引用或输出)组成,按从左到右的顺序考虑。出于这些目的,在形式参数的类型中出现的方法的任何类型参数都不是通过其名称来标识的,而是通过其在方法的类型参数列表中的顺序位置来标识的。方法的签名不包括返回类型、可能为最右边的参数指定的
params
修饰符,也不包括可选的类型参数约束

[……]

虽然
out
ref
参数修饰符被视为签名的一部分,但在单个类型中声明的成员不能仅通过
ref
out
在签名上有所不同。如果两个成员声明为同一类型,且签名相同,则会发生编译时错误。如果两个方法中带有
out
修饰符的所有参数都更改为
ref
修饰符,则签名相同。对于签名匹配的其他目的(例如隐藏或覆盖),
ref
out
被视为签名的一部分,彼此不匹配。(此限制是为了使C程序能够轻松翻译,以便在公共语言基础设施(CLI)上运行,该基础设施不提供定义仅在
ref
out
中不同的方法的方法)

让我们编写一些代码:

static void M1(int y)
{
    Console.WriteLine("val");
}

static void M1(ref int y)
{
    Console.WriteLine("ref");
}

//static void M1(out int y)  // compile error
//{
//    Console.WriteLine("out");
//}

static void Main2()
{
    int a = 3;

    M1(a);
    M1(ref a);
//    M1(out a);

}
只有
ref
out
版本之间存在冲突。注释掉
out
参数方法,它按预期编译和运行:输出为
val
ref

public void Max(int x, int y)          
//No Error
public void Max(ref int x, ref int y)  
//No Error
public void Max(out int x, out int y)  
//cannot define an overloaded method that differs only on parameter modifiers 'out' and 'ref'
第一个和第二个方法可以重载。
但是第二个和第三个方法不能重载,因为ref和out在运行时的处理方式不同,但在编译时的处理方式相同,但它们已经足够了。请注意,最后两个重载是互斥的。尽管ref和out关键字会导致不同的运行时行为,但它们在编译时不被视为方法签名的一部分。