Почему локальные переменные должны иметь начальные значения - PullRequest
7 голосов
/ 15 апреля 2009

Почему я должен инициализировать переменные внутри методов?

int test1; // Not initialized, but ok

public int Foo()
{
   int test2;                 // Not initialized

   int test3 = test1;         // Ok
   int test4 = test2;         // An error
}

Ответы [ 4 ]

15 голосов
/ 16 апреля 2009

Поля автоматически инициализируются для логического нуля для типа; это неявно. Переменные должны подчиняться «определенному присваиванию», поэтому должно быть присвоено , прежде чем их можно будет прочитать.

ECMA 334v4

§17.4.4 Инициализация поля

Начальное значение поля, будь то это будет статическое поле или экземпляр поле, является значением по умолчанию (§12.2) из тип поля. Это невозможно наблюдать значение поля перед эта инициализация по умолчанию имеет произошло, и поле, таким образом, никогда "Инициализирован".

и

§12. Переменные

... Переменная должна быть определенно назначена (§12.3) до ее значение может быть получено. ...

12 голосов
/ 01 августа 2010

Расширяя ответ Марка, инициализация локальной переменной также связана с процессом проверки .
CLI требует, чтобы в любом проверяемом коде (то есть в модулях, которые явно не просили пропустить процесс проверки с помощью свойства SkipVerfication из атрибута SecurityPermission ), все локальные переменные должны быть инициализированы до того, как они использование. В противном случае будет выдано VerficationException .

Более интересно то, что компилятор автоматически добавляет флаг .locals init в каждый метод, который использует локальные переменные. Этот флаг заставляет JIT-компилятор генерировать код, который инициализирует все локальные переменные их значениями по умолчанию. Это означает, что даже если вы уже инициализировали их в своем собственном коде, JIT будет соблюдать флаг .locals init и сгенерирует правильный код инициализации. Эта «дублирующая инициализация» не влияет на производительность, поскольку в конфигурациях, которые допускают оптимизацию, JIT-компилятор обнаружит дублирование и будет эффективно рассматривать его как «мертвый код» (автоматически сгенерированная процедура инициализации не будет отображаться в сгенерированных инструкциях на ассемблере).

По словам Microsoft (также при поддержке Эрика Липперта в ответ на вопрос в своем блоге), в большинстве случаев, когда программисты не инициализируют свою локальную переменную, они этого не делают, потому что они передают на основной среда для инициализации их переменной значениями по умолчанию, но только потому, что они «забыли», таким образом, вызывая иногда иллюзорные логические ошибки.
Таким образом, чтобы уменьшить вероятность появления ошибок такого рода в коде C #, компилятор по-прежнему настаивает на том, чтобы вы инициализировали свои локальные переменные. Даже при том, что он собирается добавить флаг .locals init к сгенерированному IL-коду.

Более подробное объяснение по этому вопросу можно найти здесь: Позади .locals init Flag

4 голосов
/ 16 апреля 2009

Это на самом деле не должно. Ваша ошибка должна быть во второй строке, а не в первой, и должна быть связана с тем, что вы ИСПОЛЬЗУЛИ ЕГО, прежде чем инициализировали ее.

Здесь вам поможет компилятор.

Так что не инициализируйте их как привычку, вместо этого позвольте компилятору помочь вам!

Приятно то, что это будет проверка пути для вас. Если у вас есть оператор switch с 3 случаями, в которых каждый устанавливает значение, но вы забыли установить его в «по умолчанию», но потом использовать его, он предупредит вас, что вы пропустили путь.

Если вы инициализируете переменные равными = 0, вы извлекаете это преимущество.

2 голосов
/ 16 апреля 2009

Как указывает Марк, так говорится в спецификации. Причиной этого является то, что есть некоторые веские причины оставить элемент неинициализированным, а не локальной переменной, время жизни которой ограничено тем методом, в котором он находится. В большинстве случаев вы захотите этого только по соображениям производительности, если переменная дорогая для инициализации, и должна инициализироваться только при определенных сценариях использования. Со своей стороны, я бы избегал неинициализированных членов, пока моя спина не будет действительно против стены!

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

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