logo search
C#, 320 стр

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

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

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

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

Давайте обратимся к примеру. В класс Testing добавлен метод с именем ScopeVar, вызываемый в процедуре Main. Вот код этого метода:

/// <summary>

/// Анализ области видимости переменных

/// </summary>

/// <param name="x"></param>

public void ScopeVar(int x)

{

//int x=0;

int y =77; string s = name;

if (s=="Точка1")

{

int u = 5; int v = u+y; x +=1;

Console.WriteLine("y= {0}; u={1};

v={2}; x={3}", y,u,v,x);

}

else

{

int u= 7; int v= u+y;

Console.WriteLine("y= {0}; u={1}; v={2}", y,u,v);

}

//Console.WriteLine("y= {0}; u={1}; v={2}",y,u,v);

//Локальные переменные не могут быть статическими.

//static int Count = 1;

//Ошибка: использование sum до объявления

//Console.WriteLine("x= {0}; sum ={1}", x,sum);

int i;long sum =0;

for(i=1; i<x; i++)

{

//ошибка: коллизия имен: y

//float y = 7.7f;

sum +=i;

}

Console.WriteLine("x= {0}; sum ={1}", x,sum);

}//ScopeVar

Заметьте, в теле метода встречаются имена полей, аргументов и локальных переменных. Эти имена могут совпадать. Например, имя x имеет поле класса и формальный аргумент метода. Это допустимая ситуация. В языке C# разрешено иметь локальные переменные с именами, совпадающими с именами полей класса, - в нашем примере таким является имя y; однако, запрещено иметь локальные переменные, имена которых совпадают с именами формальных аргументов. Этот запрет распространяется не только на внешний уровень процедурного блока, что вполне естественно, но и на все внутренние блоки.

В процедурный блок вложены два блока, порожденные оператором if. В каждом из них объявлены переменные с одинаковыми именами u и v. Это корректные объявления, поскольку время существования и области видимости этих переменных не пересекаются. Итак, для невложенных блоков разрешено объявление локальных переменных с одинаковыми именами. Заметьте также, что переменные u и v перестают существовать после выхода из блока, так что операторы печати, расположенные внутри блока, работают корректно, а оператор печати вне блока приводит к ошибке, - u и v здесь не видимы, кончилось время их жизни. По этой причине оператор закомментирован.

Выражение, проверяемое в операторе if, зависит от значения поля name. Значение поля глобально для метода и доступно всюду, если только не перекрывается именем аргумента (как в случае с полем x) или локальной переменной (как в случае с полем y).

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