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.
paramsoverride in the second example andString.Formattests that the array is populated before it proceeds to iterate over the collection and insert values.