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