Материал предоставлен https://it.rfei.ru

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

Все переменные, использовавшиеся в предыдущих примерах программ, объявлялись в самом начале метода Main(). Но в C# локальную переменную разрешается объявлять в любом кодовом блоке. Как пояснялось в главе Основные элементы языка C#, кодовый блок начинается открывающей фигурной скобкой и оканчивается закрывающей фигурной скобкой. Этот блок и определяет область действия. Следовательно, всякий раз, когда начинается блок, образуется новая область действия. Прежде всего область действия определяет видимость имен отдельных элементов, в том числе и переменных, в других частях программы без дополнительного уточнения. Она определяет также время существования локальных переменных.

В C# к числу наиболее важных относятся области действия, определяемые классом и методом. Рассмотрение области действия класса (и объявляемых в ней переменных) придется отложить до того момента, когда в этом курсе будут описываться классы. А до тех пор будут рассматриваться только те области действия, которые определяются методом или же в самом методе.

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

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

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

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

// Продемонстрировать область действия кодового блока.

using System;

class ScopeDemo {
  static void Main() {
    int x;  // Эта переменная доступна для всего кода внутри метода Main().
    x = 10;
    if (x == 10) {  // начать новую область действия
      int у = 20;  // Эта переменная доступна только в данном кодовом блоке.

      // Здесь доступны обе переменные,  х и у.

      Console.WriteLine("х и у:  " + x + " " + у);
      x = у * 2;
    }
    // у = 100;  // Ошибка!  Переменная у здесь недоступна.

    // А переменная х здесь по-прежнему доступна.
    Console.WriteLine("х равно " + x);
  }
}

Как поясняется в комментариях к приведенной выше программе, переменная x объявляется в начале области действия метода Main(), и поэтому она доступна для всего последующего кода в пределах этого метода. В блоке условного оператора if объявляется переменная y. А поскольку этот кодовый блок определяет свою собственную область действия, то переменная у видима только для кода в пределах данного блока. Именно поэтому строка line y = 100;, находящаяся за пределами этого блока, закомментирована. Если удалить находящиеся перед ней символы комментария (//), то во время компиляции программы произойдет ошибка, поскольку переменная y невидима за пределами своего кодового блока. В то же время переменная x может использоваться в блоке условного оператора if, поскольку коду из этого блока, находящемуся во вложенной области действия, доступны переменные, объявленные в охватывающей его внешней области действия.

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

Если в объявление переменной включается инициализатор, то такая переменная инициализируется повторно при каждом входе в тот блок, в котором она объявлена. Рассмотрим следующий пример программы.

// Продемонстрировать время существования переменной.

using System;

class VarlnitDemo {
  static void Main() {
    int x;

    for (x = 0; x < 3; x++) {
      int y = -1;  // Переменная у инициализируется при каждом входе в блок.
      Console.WriteLine("y равно: " + y);  // Здесь всегда выводится -1

      y = 100;

      Console.WriteLine("y теперь равно: " + y);
    }
  }
}

Ниже приведен результат выполнения этой программы.

y равно:  -1
y теперь равно:  100
y равно:  -1
y теперь равно:  100
y равно:  -1
y теперь равно:  100

Как видите, переменная y повторно инициализируется одним и тем же значением -1 при каждом входе во внутренний цикл for. И несмотря на то, что после этого цикла ей присваивается значение 100, оно теряется при повторной ее инициализации.

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

/*
В этой программе предпринимается попытка объявить во внутренней области действия переменную с таким же самым именем,  как и у переменной,  определенной во внешней области действия.
*** Эта программа не может быть скомпилирована.  ***
*/

using System;

class NestVar {
  static void Main()   {
    int count;

    for(count = 0;  count < 10;  count = count+1)   {
      Console.WriteLine ("Это подсчет: " + count);

      int count;  // Недопустимо!!!
      for(count = 0;  count < 2;  count++)
        Console.WriteLine("В этой программе есть ошибка!");
    }
  }
}

Если у вас имеется некоторый опыт программирования на C или C++, то вам должно быть известно, что на присваивание имен переменным, объявляемым во внутренней области действия, в этих языках не существует никаких ограничений. Следовательно, в C и C++ объявление переменной count в кодовом блоке, входящем во внешний цикл for, как в приведенном выше примере, считается вполне допустимым. Но в C и C++ такое объявление одновременно означает сокрытие внешней переменной. Разработчики C# посчитали, что такого рода сокрытие имен может легко привести к программным ошибкам, и поэтому решили запретить его.

Неявно типизированные переменныеПреобразование и приведение типов