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();