Предупреждение о нулевой ссылке Visual Studio - почему нет ошибки?
-
06-07-2019 - |
Вопрос
Я заметил кое-что необычное в Visual Studio.Сначала попробуйте ввести это (C #) где-нибудь в функции:
class Foo
{
public void Bar()
{
string s;
int i = s.Length;
}
}
Теперь, сразу же после этого, это будет означать s
в s.Length
в качестве ошибки, говоря "Use of unassigned local variable 's'
".С другой стороны, попробуйте этот код:
class Foo
{
private string s;
public void Bar()
{
int i = s.Length;
}
}
Он скомпилирует и подчеркнет s
в private string s
с предупреждением, гласящим: "Field 'Foo.s' is never assigned to, and will always have its default value null
".
Теперь, если VS настолько умен и знает, что s всегда будет равно null, почему получение его длины во втором примере не является ошибкой?Мое первоначальное предположение было: "Это выдает ошибку компиляции только в том случае, если компилятор просто не может завершить свою работу.Поскольку технически код выполняется до тех пор, пока вы никогда не вызываете Bar() , это всего лишь предупреждение ". За исключением того, что объяснение недействительно в первом примере.Вы все еще можете запустить код без ошибок, если никогда не вызываете Bar().Так что же это дает?Просто оплошность, или я что-то упускаю?
Решение
Первый пример (ошибка) - это пример Отслеживание с определенным назначением , которое применяется только к локальным переменным. Из-за ограниченного контекста, компилятор имеет сжатый контроль над этой ситуацией. Обратите внимание, что s
не является нулевым, оно не определено.
Во втором примере s
является полем (по умолчанию равно нулю). Нет ошибки компилятора, но она всегда будет обнаружена во время выполнения. Этот конкретный случай может быть пойман в ловушку, но этот тип ошибки в общем случае не обнаруживается компилятором.
Например, вы можете добавить метод Bar2 ()
, который назначает строку для s
, но вызывает ее позже, чем Bar ()
, или не все. Это устранило бы предупреждение, но не ошибку времени выполнения.
Так и есть по замыслу.
Другие советы
Для второго примера код допустим, он просто может выполняться некорректно.Вот несколько случаев, в которых эта программа могла бы "успешно" выполняться
- Компилятор не корректен на 100%.Возможно, что "s" будет иметь ненулевое значение, если экземпляр будет изменен с помощью отражения.
- Программа может выполняться без ошибок, если метод Bar никогда не вызывается
- Эта программа может быть тестовой программой, которая запускает исключение NullReferenceException по причинам тестирования
Единственное, что я могу предположить, это то, что во втором примере s можно изменить с помощью отражения (используя BindingFlags.Private для доступа к закрытому члену).
В первом примере s является локальной переменной, и компилятор может легко проверить, что переменная s не была назначена перед ее использованием.
Во втором случае s является глобальной переменной, и, возможно, она была инициализирована где-то еще в классе.