空字面量参数类型重载解析

9

可能重复:
当传递null值作为参数时,方法重载解析系统如何决定调用哪个方法?

这是一个关于编译器在将null字面量作为参数传递时选择特定重载的问题,以string.Format重载为例。

使用null字面量作为args参数时,string.Format会抛出ArgumentNullException异常。

string.Format("foo {0}", null);

Format方法有一些重载。

string.Format(string, object);
string.Format(string, object[]);
string.Format(IFormatProvider, string, object[]);

浏览反编译后的代码,可以看到对于空文本参数的异常是从第二个方法抛出的。然而下面的示例调用了上述第一个方法(和预期一样),接着该方法会调用第二个方法,最终返回"foo"。

string x = null;
string.Format("foo {0}", x);

string y;
string.Format("foo {0}", y = null);

但是string.Format("foo {0}", null)调用了上面的第二个方法,并导致了一个空异常。为什么编译器会在这种情况下决定将null字面量与第二个方法签名匹配而不是第一个方法?


3
如果这个范围不仅限于字符串格式化的情况,可能需要扩大标题/范围以包括更一般意义上的可变参数。 - user166390
Pete,你可能已经意识到这一点了(这不是对你问题的回答),但我想提一下:为了避免这个异常,你可以使用String.Format("Testing {0}", String.Empty)。祝一切顺利。 - MoonKnight
2
重复问题:https://dev59.com/ZG435IYBdhLWcg3w20B8。简而言之:重载决议更喜欢更具体的类型。因此,它选择数组,因为“object”是.NET中最不具体的类型。 - Jan
@Jan:这是否也解释了为什么另外两个示例选择对象而不是对象[]? - Peter Kelly
在您的另外两个示例中,由于string不是一个object[],因此无法使用带有object[]参数的重载,在该情况下参数的类型为string - Jan
@Peter Kelly:在另外两种情况下,您声明传递的是字符串。因此,它不可能匹配object[],而是匹配object。 - Chris
2个回答

3

我猜测object[]object更具体,而且由于null可赋值给object[],所以选择前者。(参见C#规范7.5.3.2中的更好的函数成员)。

如果尝试相同的操作,则会发生相同的情况:

void Foo(object o) {}
void Foo(object[] arr) {}

Foo(null); //Foo(object[]) gets called.

0

不能给你100%的确定性,但我最好的猜测如下...

如果我亲自编写一个编译器,并且必须根据传递的参数选择使用哪个重载函数,我自然会迭代列表并找到最佳匹配。我想C#编译器中实现了类似的功能。

因此,这就提示我,要么“overload 2”(在您的示例中)位于“overload 1”之前,因此找到匹配项并中断迭代,要么编译器设置为使用更后面的匹配项。

当然,在您的第二个示例中传递x和y。将字符串与对象进行匹配很容易,因此可以匹配到“overload 1”,而字符串无法匹配到object[],因此“overload 2”不是有效的匹配项。

当您直接传递null时,这将匹配到“overload 1”和“overload 2”,因此回到列表中找到的第一个或最后一个点。

编辑:结果发现,编译器基本上是根据哪些参数更具体来决定的。如果object[]比object更具体,则使用object[]。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接