How does string.Format handle null values?

In case you use an interpolated string ($"", another way to format), the null is ignored, skipped. So

string nullString = null;
Console.WriteLine($"This is a '{nullString}' in a string");

will produce: "This is a '' in a string". Of course you can use the null coalescing operator in case of null to produce the output needed:

string nullString = null;
Console.WriteLine($"This is a '{nullString ?? "nothing"}' in a string");

In your first example, you are hitting Format(String, Object), which looks like this when disassembled:

 public static string Format(string format, object arg0)
 {
    return Format(null, format, new object[] { arg0 });
 }

Note the new object[] around that.

The second one, you are apparently hitting the Format(string, object[]) usage, at least that is the one being invoked when I perform the same test. Disassembled, that looks like this:

 public static string Format(string format, params object[] args)
 {
     return Format(null, format, args);
 }

So all of these actually get funneled to Format(IFormatProvider, string, object[]). Cool, let's look at the first few lines there:

public static string Format(IFormatProvider provider, string format, params object[] args)
{
    if ((format == null) || (args == null))
    {
        throw new ArgumentNullException((format == null) ? "format" : "args");
    }
...
}

...welp, there's your problem, right there! The first invocation is wrapping it in a new array, so it's not null. Passing in null explicitly doesn't make it do that, due to the specific instance of Format() that's calling.


The first call gets resolved as a call to Format(object), while the second gets resolved as a call to Format(object[]). Null parameters are handled differently by these different overloads.

Overload resolution is described here. The relevant part is that for the second call to Format, an overload of Format(params object[]) gets expanded to Format(object[]), which is preferred to Format(object). The literal null is both an object[] and an object, but object[] is more specific, so that is chosen.


I'm guessing here, but it looks to be the difference of which overloaded call you're hitting; String.Format has multiple.

In the first example, it would make sense you're hitting String.Format(string,object).

In the second example by providing null you're most likely hitting String.Format(string,params object[]) which, per the documentation, would raise an ArgumentNullException when:

format or args is null.

If you're running .NET4, try using named parameters:

String.Format("Another exception occured: {0}", arg0: null);

Why is it hitting the params object[] overload? Probably because null isn't an object, and the way params works is that you can pass either each value as a new object in the call or pass it an array of the values. That is to say, the following are one in the same:

String.Format("Hello, {0}! Today is {1}.", "World", "Sunny");
String.Format("Hello, {0}! Today is {1}.", new Object[]{ "World", "Sunny" })

So it's translating your statement call to something along the lines of:

String format = "Another exception occured: {0}";
Object[] args = null;
String.Format(format, args); // throw new ArgumentNullException();