Предупреждение о нулевой ссылке на Visual Studio - почему нет ошибки? - PullRequest
5 голосов
/ 12 сентября 2009

Я заметил нечто особенное в 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 всегда будет нулевым, почему не ошибка получить его длину во втором примере? Моим первоначальным предположением было: «Это дает ошибку компиляции, только если компилятор просто не может завершить свою работу. Поскольку код технически выполняется до тех пор, пока вы никогда не вызываете Bar (), это всего лишь предупреждение». За исключением того, что объяснение недействительно в первом примере. Вы по-прежнему можете запускать код без ошибок, если вы никогда не вызываете Bar (). Так что же дает? Просто недосмотр или я что-то упустил?

Ответы [ 4 ]

8 голосов
/ 12 сентября 2009

Первый пример (ошибка) - это пример отслеживания определенного назначения компилятора, который применяется только к локальным переменным. Из-за ограниченного контекста, компилятор имеет сжатый контроль над этой ситуацией. Обратите внимание, что s не равно нулю, оно не определено.

Во втором примере s - это поле (по умолчанию ноль). Нет ошибки компилятора, но она всегда будет обнаружена во время выполнения. Этот конкретный случай может быть пойман в ловушку, но этот тип ошибки в общем случае не обнаруживается компилятором.
Например, вы можете добавить метод Bar2(), который присваивает строку s, но вызывает ее позже, чем Bar(), или не делает этого вообще. Это устранило бы предупреждение, но не ошибку времени выполнения.

Так и есть по замыслу.

3 голосов
/ 12 сентября 2009

Для второго примера код действителен, он может работать некорректно. Вот несколько случаев, когда эта программа могла выполняться «успешно»

  • Компилятор не на 100% корректен. «S» может иметь ненулевое значение, если экземпляр изменен с помощью отражения.
  • Программа может выполняться без ошибок, если метод Bar никогда не вызывается
  • Эта программа может быть тестовой программой, которая по причинам тестирования вызывает исключение NullReferenceException
0 голосов
/ 12 сентября 2009

В первом примере s - локальная переменная, и компилятор может легко проверить, что переменная s не была назначена перед ее использованием.

Во втором * s - глобальная переменная, и, возможно, она была инициализирована где-то еще в классе.

0 голосов
/ 12 сентября 2009

Единственное, что я могу предположить, это то, что во втором примере s можно изменить с помощью отражения (используя BindingFlags.Private для доступа к закрытому члену).

...