Инициализация полей экземпляров по сравнению с локальными переменными

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

  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'
    }
  }

Ответ 1

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

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

Ответ 2

Он управляется определенными правилами назначения в С#. Переменная должна быть определенно назначена до ее доступа.

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

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

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

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

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

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

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

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

  • Параметры значения.

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

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

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

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

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

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

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

Ответ 3

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

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

Ответ 4

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

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

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

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

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

Ответ 5

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

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

Ответ 6

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

Ответ 7

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

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