Инициализация полей экземпляра против локальных переменных - PullRequest
18 голосов
/ 09 октября 2009

Мне всегда было интересно, почему в следующем примере можно не инициализировать поле экземпляра (полагая, что оно будет иметь значение по умолчанию) и получить к нему доступ, тогда как локальные переменные, по-видимому, должен быть инициализирован, даже если я инициализирую его значением по умолчанию, оно все равно получит ...

  public class TestClass
  {
    private bool a;

    public void Do()
    {
      bool b; // That would solve the problem: = false;
      Console.WriteLine(a);
      Console.WriteLine(b); //Use of unassigned local variable 'b'
    }
  }

Ответы [ 7 ]

29 голосов
/ 09 октября 2009

Для локальных переменных компилятор имеет хорошее представление о потоке - он может видеть «чтение» переменной и «запись» переменной и доказывать (в большинстве случаев), что первая запись произойдет раньше первое чтение.

Это не относится к переменным экземпляра. Рассмотрим простое свойство - как узнать, установит ли кто-нибудь его до того, как получит? Это делает практически невозможным применение разумных правил - поэтому вам нужно либо убедиться, что все поля были заданы в конструкторе, либо позволить им иметь значения по умолчанию. Команда C # выбрала последнюю стратегию.

6 голосов
/ 09 октября 2009

Это регулируется определенными правилами присваивания в C #. Переменная должна быть обязательно назначена до того, как к ней будет получен доступ.

5.3 Определенное назначение

В данном месте в исполняемом коде члена функции говорят, что переменная определенно назначена, если компилятор может доказать, посредством определенного статического анализа потока (§5.3.3), что переменная была автоматически инициализирована или был целью по крайней мере одного назначения.

5.3.1 Первоначально назначенные переменные

Следующие категории переменных классифицируются как изначально присвоенные:

  • Статические переменные.

  • Переменные экземпляра экземпляров класса.

  • Переменные экземпляра изначально назначенных переменных структуры.

  • Элементы массива.

  • Значения параметров.

  • Справочные параметры.

  • Переменные, объявленные в предложении catch или в выражении foreach.

5.3.2 Первоначально неназначенные переменные

Следующие категории переменных классифицируются как изначально неназначенные:

  • Переменные экземпляра изначально неназначенных переменных структуры.

  • Выходные параметры, включая эту переменную конструкторов экземпляра структуры.

  • Локальные переменные, кроме тех, которые объявлены в предложении catch или в выражении foreach.

2 голосов
/ 09 октября 2009

Когда часть памяти выделяется для нового экземпляра объекта, среда выполнения записывает нули по всему блоку, гарантируя, что новый объект начинается в известном состоянии - поэтому целые числа по умолчанию равны 0, удваивают значение по умолчанию до 0,0, указатели & ссылки на объекты на null и т. д.

Теоретически можно сделать то же самое для стека кадров, выделенных как часть вызовов методов. Затраты, хотя и были бы высокими - это резко замедлило бы вызовы других методов, и, следовательно, не предпринималось.

1 голос
/ 09 октября 2009

Это действительно вопрос того, что может сказать вам предупреждение. На самом деле предупреждение не может быть уверенным в том, что какой-то другой метод не инициализировал переменную класса, поэтому он предупреждает только тот, который может быть уверен, что он не инициализирован.

Кроме того, это предупреждение, а не ошибка, потому что технически нет ничего плохого в использовании неназначенной переменной (она гарантированно будет 'ложной'), но, вероятно, логическая ошибка - не назначать ее.

1 голос
/ 09 октября 2009

Неявный конструктор инициализирует переменную экземпляра для вас. Даже когда вы указываете c'tor, но не инициализируете поле, это делается для вас как часть создания объекта в куче. Это не относится к локальным переменным стека.

1 голос
/ 09 октября 2009

Это ограничение компилятора. Компилятор пытается запретить вам использовать неназначенную переменную везде, где это возможно, и это хорошо, так как использование неинициализированных переменных раньше было распространенным источником ошибок в старом C-коде.

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

1 голос
/ 09 октября 2009

Переменные экземпляра имеют значение по умолчанию. Из спецификации C # 3.0:

5.1.2.1 Переменные экземпляра в классах

приходит переменная экземпляра класса в существование, когда новый экземпляр этот класс создан, и перестает существуют, когда нет ссылок на этот экземпляр и экземпляр финализатор (если есть) выполнен.

Начальное значение экземпляра переменная класса по умолчанию значение (§5.2) типа переменной.

Для определенного назначения проверка, переменная экземпляра считается изначально назначенным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...