Question

In the following code below, why do the two string.Format calls not behave the same way? In the first one, no exception is thrown, but in the second one an ArgumentNullException is thrown.

static void Main(string[] args)
{
    Exception e = null;
    string msgOne = string.Format("An exception occurred: {0}", e);
    string msgTwo = string.Format("Another exception occurred: {0}", null);
}

Could someone please help me understand the difference between the two?

Was it helpful?

Solution

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

OTHER TIPS

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.

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

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.

There are two differences which are following:

  1. Here, Null value is assigned.

    Exception e = null;
    string msgOne = string.Format("An exception occurred: {0}", e);
    
  2. Here, Null value cannot be read in string format which means type casting error.

    string msgTwo = string.Format("Another exception occurred: {0}", null);
    

I give you simple example: Here, You cannot read the NULL value as a string format.

string str = null.toString();
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top