(Информацию о новом помощнике по исключениям в Visual Studio 2017 см. В конце этого ответа)
Рассмотрим этот код:
String s = null;
Console.WriteLine(s.Length);
Это вызовет появление NullReferenceExceptionво второй строке, и вы хотите знать, почему .NET не сообщает вам, что это sбыло null, когда было создано исключение.
Чтобы понять, почему вы не получаете эту информацию, вы должны помнить, что выполняется не исходный код C #, а скорее IL:
IL_0001: ldnull
IL_0002: stloc.0 // с
IL_0003: ldloc.0 // с
IL_0004: callvirt System.String.get_Length
IL_0009: вызов System.Console.WriteLine
Это callvirtкод операции, который генерирует NullReferenceExceptionи делает это, когда первым аргументом в стеке оценки является пустая ссылка (та, которая была загружена с использованием ldloc.0).
Если .NET сможет определить, что это sбыла пустая ссылка, он должен каким-то образом отследить, что первый аргумент в стеке оценки возник из формы s. В этом случае нам легко увидеть, что это sбыло null, но что, если бы значение было возвращенным значением из другого вызова функции и не сохранено в какой-либо переменной? В любом случае, такая информация - не то, что вы хотите отслеживать на виртуальной машине, такой как виртуальная машина .NET.
Чтобы избежать этой проблемы, я предлагаю вам выполнять проверку нулевого аргумента во всех вызовах общедоступных методов (если, конечно, вы не разрешаете нулевую ссылку):
public void Foo(String s) {
if (s == null)
throw new ArgumentNullException("s");
Console.WriteLine(s.Length);
}
Если методу передается null, вы получаете исключение, которое точно описывает, в чем проблема (то sесть null).
Четыре года спустя в Visual Studio 2017 появился новый помощник по исключениям, который попытается определить, что имеет значение null при NullReferenceExceptionвызове. Он даже может предоставить вам необходимую информацию, когда это возвращаемое значение метода имеет значение NULL:

Обратите внимание, что это работает только в сборке DEBUG.