59

If I run this code:

Console.WriteLine( String.Format( "{0}", null ) );

I get a ArgumentNullException but if I run this code:

String str = null;
Console.WriteLine( String.Format( "{0}", str ) );

it runs just fine and the output is an empty string.

Now the two piece look equivalent to me - they both pass a null reference into String.Format() yet the behavior is different.

How id different behavior possible here?

John Saunders
  • 160,644
  • 26
  • 247
  • 397
sharptooth
  • 167,383
  • 100
  • 513
  • 979
  • 3
    Console.WriteLine( String.Format( "{0}", (object)null )); This is fine too. Weird. – Dave Bish Dec 14 '12 at 11:11
  • String.Format must be doing some work on the 2nd example, perhaps turning it into the null char? `\0` – SpaceBison Dec 14 '12 at 11:14
  • @DaveBish Hopefully Jon Skeet can answer why your example doesn't throw an exception. – juharr Dec 14 '12 at 11:25
  • The first case is passing in a null reference. The second case is passing in a (non-null) reference to a null string. Fine but significant distinction. Edit: I am not that familiar with C#, but I am assuming "String str = null;" is assigning a value to a declared object. If that's not the case, then I'm probably in error. – CuriousRabbit Dec 18 '12 at 22:58

1 Answers1

76

Just decompile the code to work out what's going on.

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

calls the most specific applicable overload, which is string.Format(string, object[]).

The overloads of string.Format are:

Format(String, Object)
Format(String, Object[])
Format(IFormatProvider, String, Object[])
Format(String, Object, Object)
Format(String, Object, Object, Object)

Hopefully it's obvious why the last three options are invalid.

To work out which of the first two to use, the compiler compares the conversion from null to Object to the conversion from null to Object[]. The conversion to Object[] is deemed "better" because there's a conversion from Object[] to Object, but not vice versa. This is the same logic by which if we had:

Foo(String)
Foo(Object)

and called Foo(null), it would pick Foo(String).

So your original code is equivalent to:

object[] values = null;
string.Format("{0}", values);

At this point, hopefully you'd expect an ArgumentNullException - as per the documentation.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 1
    I bet you meant `string.Format("{0}", values);` on your last line of code. Anyway, there goes a +1 for typing what I was typing, just faster and more accurately ^^' – Edurne Pascual Dec 14 '12 at 11:18
  • 3
    Where is the `take my money` button? – Soner Gönül Dec 14 '12 at 11:19
  • Also, maybe the answer should highlight *why* the compiler picks the most specific version of the function (it's easy to figure out for me, and I know it's even easier for you, but many readers may miss the detail that a `null` literal carries as little type information as a blank piece of paper). – Edurne Pascual Dec 14 '12 at 11:21
  • Why doesn't `string.Format("{0}", (object)null)` throw an exception? And the docs only mention an exception if the format is null, not the args. – juharr Dec 14 '12 at 11:23
  • Try using F12 (go to definition) @juharr, and you will see the difference. It is, in general, very bad practice to supply null for a params argument which is what null without a typecast to object results in. – Johny Skovdal Dec 14 '12 at 11:25
  • @juharr: The docs I linked to state that `ArgumentNullException` is thrown if "format or args is Nothing." - were you looking at the docs for `string.Format(string, object)` perhaps? – Jon Skeet Dec 14 '12 at 11:26
  • 1
    @juharr having one (or more, or all) member of the object array to be null is fine. Having the array itself being null ain't. It'd be nice for the `string.Format(string, object[])` version to default null arrays into empty ones, but it just doesn't do that. – Edurne Pascual Dec 14 '12 at 11:27
  • @JonSkeet OK, I see now. The `null` is passed as a object array if you don't cast it to object. Casting to object results in the overload that just takes one object parameter. – juharr Dec 14 '12 at 11:29