9

Possible Duplicate:
How does the method overload resolution system decide which method to call when a null value is passed?

This is a question about why the compiler chooses a certain overload when passed a null literal as a parameter, demonstrated by string.Format overloads.

string.Format throws an ArgumentNullException when using null literal for args parameter.

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

The Format method has some overloads.

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

Running through the decompiled code, the exception for the null literal args is thrown from the second method. However, the following examples call the first method above (as expected) and then that calls the second which calls the third eventually returning just "foo".

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

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

But string.Format("foo {0}", null) calls the second method above and results in a null exception. Why does the compiler decide that the null literal matches the second method signature instead of the first in this case?

Community
  • 1
  • 1
Peter Kelly
  • 14,253
  • 6
  • 54
  • 63
  • 3
    Perhaps broaden the title/scope if this encompasses varargs in a more general sense (if it's not string.Format specific)... –  Sep 13 '11 at 09:34
  • Pete, you are probably aware of this (and it is not an answer to you question) but though I would mention it; to avoid this exception you can use `String.Format("Testing {0}", String.Empty);`. All the best. – MoonKnight Sep 13 '11 at 09:42
  • 2
    Duplicate question: http://stackoverflow.com/q/5173339/25727. In short: Overload resolution prefers more specific types. So it chooses the array because `object` is the most unspecific type in .NET. – Jan Sep 13 '11 at 09:42
  • @Jan: Does that also explain why the other two examples choose object instead of object[]? – Peter Kelly Sep 13 '11 at 09:48
  • In your other two examples the overload with the `object[]` parameter can't be used because `string` is not an `object[]` and the type of the parameter is `string` in that case. – Jan Sep 13 '11 at 09:51
  • @Peter Kelly: In the case of the other two you are declaring that what you are passing is a string. There is no possibility therefore that it can match object[] so it matches object instead. – Chris Sep 13 '11 at 09:51

2 Answers2

3

I would simply guess that object[] is more specific than object and being null assignable to object[] the former is picked. (7.5.3.2 Better function member in the C# specs).

Same happens if you try:

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

Foo(null); //Foo(object[]) gets called.
InBetween
  • 32,319
  • 3
  • 50
  • 90
0

Cannot give you 100% certainty but my best guess would be as follows...

If I was personally writing a compiler and I had to cope with choosing which overloaded function to use based on passed parameters I would naturally iterate the list and find the best match. I imagine there is something along these lines implemented in the C# compiler.

So, this would suggest to me that either "overload 2" (in your example) is earlier in the list than "overload 1" and thus a match is found and the iteration broken, OR the compiler is set to use the more latter matching overload.

Of course, in your 2 example passing x and y. It is easy to match to "overload 1" as you are matching a string to object, whereas a string cannot match to object[] and therefore "overload 2" is not a valid match.

When you directly pass null then this matches to both "overload 1" and "overload 2" so back to the point of being either the first found in the list or the last found.

EDIT: So it turns out that the compiler essential decides based on which parameters are more specific. And object[] if more specific that object.

musefan
  • 47,875
  • 21
  • 135
  • 185