Почему я получаю исключение при передаче "нулевой" константы, но не при передаче "нулевой" ссылки на строку?

Если я запустил этот код:

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

Я получаю ArgumentNullException, но если я запустил этот код:

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

он работает просто отлично, а выход - пустая строка.

Теперь две части выглядят эквивалентно мне - они оба передают нулевую ссылку в String.Format(), но поведение отличается.

Как здесь возможно различное поведение id?

Ответ 1

Просто декомпилируйте код, чтобы выяснить, что происходит.

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

вызывает наиболее специфическую применимую перегрузку, которая string.Format(string, object[]).

Перегрузками string.Format являются:

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

Надеюсь, это очевидно, почему последние три параметра недействительны.

Чтобы определить, какой из первых двух использовать, компилятор сравнивает преобразование из null в Object в преобразование от null до Object[]. Преобразование в Object[] считается "лучше", потому что есть преобразование от Object[] до Object, но не наоборот. Это та же логика, с помощью которой мы имели:

Foo(String)
Foo(Object)

и называется Foo(null), он выбрал бы Foo(String).

Итак, ваш исходный код эквивалентен:

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

На этом этапе, надеюсь, вы ожидаете ArgumentNullException - согласно документации.