这是一个关于为什么编译器在将null文字作为参数传递时选择某个重载的问题,由string.Format重载来演示。
当对args参数使用null literal时, string.Format会抛出ArgumentNullException
。
string.Format("foo {0}", null);
Format方法有一些重载。
string.Format(string, object);
string.Format(string, object[]);
string.Format(IFormatProvider, string, object[]);
运行反编译代码,从第二个方法抛出null literal args的异常。但是,下面的示例调用上面的第一个方法(如预期的那样)然后调用第二个调用第三个方法最终返回“foo”。
string x = null;
string.Format("foo {0}", x);
string y;
string.Format("foo {0}", y = null);
但string.Format("foo {0}", null)
调用上面的第二个方法并导致null异常。为什么编译器在这种情况下决定null文字与第二个方法签名匹配而不是第一个?
答案 0 :(得分:3)
我只是猜测object[]
比object
更具体,而null
可分配给object[]
,前者被选中。 (7.5.3.2 C#规范中更好的功能成员)。
如果您尝试,也会发生同样的情况:
void Foo(object o) {}
void Foo(object[] arr) {}
Foo(null); //Foo(object[]) gets called.
答案 1 :(得分:0)
无法100%确定,但我最好的猜测如下......
如果我亲自编写编译器并且我必须根据传递的参数来处理选择使用哪个重载函数,我自然会迭代列表并找到最佳匹配。我想在C#编译器中实现了这些内容。
所以,这会告诉我,“重载2”(在你的例子中)在列表中比“重载1”更早,因此找到匹配并且迭代被破坏,或者编译器被设置为使用更多后者匹配过载。
当然,在你传递x和y的2个例子中。当您将字符串与对象匹配时,很容易匹配“重载1”,而字符串无法与对象[]匹配,因此“重载2”不是有效匹配。
当你直接传递null然后它匹配“重载1”和“重载2”,所以回到列表中的第一个或最后找到的点。
编辑:事实证明,编译器必不可少地根据哪些参数更具体来决定。而object []如果更具体那个对象。