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

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

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

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

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

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

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

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

Элементы массива создаются при создании экземпляра массива и удаляются при отсутствии ссылок на этот экземпляр массива.

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

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

Параметры по значению

Параметр, объявленный без модификаторов ref и out, является параметром по значению.

Параметр по значению создается при вызове соответствующей функции-члена (метода, конструктора экземпляра, метода доступа или оператора) или анонимной функции, к которой относится данный параметр, и инициализируется по значению аргумента, заданного при вызове функции. Параметр по значению, как правило, удаляется при возвращении значения функцией-членом или анонимной функцией. Тем не менее, если параметр по значению перехвачен анонимной функцией (§7.15), его время жизни увеличивается на срок, пока делегат или дерево выражений, созданные из этой анонимной функции, доступны для сбора мусора.

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

Параметры ссылок

Параметр, объявленный с модификатором ref, является параметром по ссылке.

Для параметра ссылки не создается новое место хранения. Параметр по ссылке указывает место хранения переменной, заданной в качестве аргумента при вызове функции-члена или анонимной функции. Таким образом, значение параметра по ссылке всегда совпадает со значением базовой переменной.

В отношении параметров по ссылке применяются указанные ниже правила определенного присваивания. Обратите внимание на разные правила для выходных параметров, описанные в §5.1.6.

· Переменная должна быть определенно присвоена (§5.3), чтобы ее можно было передать как параметр по ссылке при вызове функции-члена или делегата.

· В функции-члене или анонимной функции параметр по ссылки считается имеющим начальное значение.

В методе экземпляра или методе доступа экземпляра с типом структуры ключевое слово this имеет точно такое же поведение, как параметр по ссылке с типом структуры (§7.6.7).

Выходные параметры

Параметр, объявленный с модификатором out, является выходным параметром.

При использовании выходного параметра не создается новое место хранения. Выходной параметр указывает место хранения переменной, заданной в качестве аргумента при вызове функции-члена или делегата. Таким образом, значение выходного параметра всегда совпадает со значением базовой переменной.

В отношении выходных параметров применяются указанные ниже правила определенного присваивания. Обратите внимание на разные правила для выходных параметров, описанные в §5.1.5.

· Для передачи переменной как выходного параметра при вызове функции-члена или делегата определенно присваивать переменную необязательно.

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

· В функции-члене или анонимной функции выходной параметр считается не имеющим начального значения.

· Каждый выходной параметр функции-члена или анонимной функции должен быть определенно присвоен (§5.3) перед нормальным завершением выполнения такой функции-члена или анонимной функции.

В конструкторе экземпляра с типом структуры ключевое слово this имеет точно такое же поведение, как выходной параметр с типом структуры (§7.6.7).

Локальные переменные

Локальная переменная объявляется с использованием объявления локальной переменной, которое может находиться в блоке, операторе for, операторе switch или операторе using, а также при помощи оператора foreach или конкретной конструкции catch в операторе try.

Время жизни локальной переменной соответствует части выполнения программы, в которой для нее гарантированно резервируется место. Это время жизни длится по меньшей мере с момента входа в блок, операторы for, switch, using, foreach или конкретную конструкцию catch, с которой связана данная переменная, до завершения выполнения этого блока, операторов for, switch, using, foreach или конкретной конструкции catch любым из способов. (Вход во вложенный блок или вызов метода приостанавливает, но не завершает выполнение текущих блока, операторов for, switch, using, foreach или конкретной конструкции catch.) Если локальная переменная перехватывается анонимной функцией (§7.15.5.1), ее время жизни увеличивается по крайней мере на период времени, в течение которого делегат или дерево выражений, созданные в этой анонимной функции, а также другие объекты, ссылающиеся на перехваченную переменную, станут доступны для сбора мусора.

Если вход в родительский блок, оператор for, switch, using, foreach или конкретную конструкцию catch выполняется рекурсивно, каждый раз создается новый экземпляр локальной переменной, при этом каждый раз вычисляется инициализатор локальной переменной (при его наличии).

Локальная переменная, созданная с использованием объявления локальной переменной, не инициализируется автоматически и поэтому не имеет значения по умолчанию. Для целей проверки определенного присваивания локальная переменная, созданная с использованием объявления локальной переменной, считается не имеющей начального значения. Объявление локальной переменной может содержать инициализатор локальной переменной. В этом случае переменная считается определенно присвоенной только после инициализирующего выражения (§5.3.3.4).

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

Локальная переменная, созданная с использованием оператора foreach или конкретной конструкции catch, считается определенно присвоенной по всей области действия.

Фактическое время жизни локальной переменной зависит от реализации. Например, компилятор может статическим образом определить, что локальная переменная в блоке используется лишь в небольшой части этого блока. В такого анализа компилятор может создать код, в котором время жизни места хранения переменной будет меньше, чем время жизни содержащего ее блока.

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

Значения по умолчанию

Указанные ниже категории переменных автоматически инициализируются соответствующими значениями по умолчанию.

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

· Переменные экземпляра класса.

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

Значение по умолчанию для переменной зависит от типа переменной и определяется следующим образом:

· Для переменной с типом значений, значение по умолчанию равно значению, вычисленному конструктором по умолчанию для типа значений (§4.1.2).

· Для переменной со ссылочным типом значением по умолчанию является null.

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

Определенное присваивание

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

· Переменная с начальным значением (§5.3.1) всегда считается определенно присвоенной.

· Переменная без начального значения (§5.3.2) считается определенно присвоенной в указанном расположении, если все возможные пути выполнения, ведущие в это расположение, содержат по меньшей мере одну из следующих операций:

o Простое присваивание (§7.17.1), в котором переменная является левым операндом.

o Выражение вызова (§7.6.5) или выражение создания объекта (§7.6.10.1), передающее переменную в качестве выходного параметра.

o Для локальной переменной — объявление локальной переменной (§8.5.1), включающее инициализатор переменной.

Формальная спецификация, определяющая изложенные выше правила, описана в разделах §5.3.1, §5.3.2 и §5.3.3.

Определенное присваивание для переменных экземпляра переменной с типом структуры отслеживаются как по отдельности, так и в совокупности. В дополнение к изложенным выше правилам в отношении переменных с типом структуры и их переменных экземпляра применяются следующие правила:

· Переменная экземпляра считается определенно присвоенной, если содержащая ее переменная с типом структуры считается определенно присвоенной.

· Переменная с типом структуры считается определенно присвоенной, если каждая из ее переменных экземпляра считается определенно присвоенной.

Определенное присваивание является обязательным в следующих контекстах:

· Переменная должна быть определенно присвоена в каждом месте, где извлекается ее значение. Это обеспечивает отсутствие неопределенных значений. Включение переменной в выражение считается извлечением значения этой переменной за исключением следующих случаев:

o переменная является левым операндом выражения простого присваивания,

o переменная передается в качестве выходного параметра, или

o переменная является переменной с типом структуры и указана как левый операнд метода доступа к члену.

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

· Все выходные параметры функции-члена должны быть определенно присвоены в каждой точке, где выполняется возврат из функции-члена (при помощи оператора return или в результате достижения конца тела функции-члена). Это гарантирует, что функции-члены не будут возвращать в выходных параметрах неопределенные значения, что позволяет компилятору обработать вызов функции-члена, принимающей переменную в качестве выходного параметра, как выполнение присваивания в отношении этой переменной.

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

Наши рекомендации