Сдам Сам

ПОЛЕЗНОЕ


КАТЕГОРИИ







Глобальные переменные уровня процедуры. Существуют ли?





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

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

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

Константы

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

y = 7.7f;

Значение константы "7.7f" является одновременно ее именем, оно же позволяет однозначно определить тип константы. Заметьте, иногда, как в данном случае, приходится добавлять к значению специальные символы для точного указания типа. Я не буду останавливаться на этих подробностях. Если возникает необходимость уточнить, как записываются литералы, то достаточно получить справку по этой теме. Делается все так же, как и в языке C++.

Всюду, где можно объявить переменную, можно объявить и именованную константу. Синтаксис объявления схож. В объявление добавляется модификатор const, инициализация констант обязательна и не может быть отложена. Инициализирующее выражение может быть сложным, важно, чтобы оно было вычислимым в момент его определения. Вот пример объявления констант:

/// <summary>/// Константы/// </summary>public void Constants(){ const int SmallSize = 38, LargeSize =58; const int MidSize = (SmallSize + LargeSize)/2; const double pi = 3.141593; //LargeSize = 60; //Значение константы нельзя изменить. Console.WriteLine("MidSize= {0}; pi={1}", MidSize, pi);}//Constants

 

Выражения

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

  • приоритет операций;
  • для операций одного приоритета порядок применения - слева направо или справа налево;
  • преобразование типов операндов и выбор реализации для перегруженных операций;
  • тип и значение результата выполнения операции над заданными значениями операндов определенного типа.

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

Приоритет и порядок выполнения операций

Большинство операций в языке C#, их приоритет и порядок наследованы из языка C++. Однако имеются и различия: например, нет операции ", ", позволяющей вычислять список выражений; добавлены уже упоминавшиеся операции checking и unchecking, применимые к выражениям.

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

Приоритет Категория Операции Порядок
  Первичные (expr) x.y f(x) a[x] x++ x-- new sizeof(t) typeof(t) checked(expr) unchecked(expr) Слева направо
  Унарные + -! ~ ++x --x (T)x Слева направо
  Мультипликативные (Умножение) - * / % Слева направо
  Аддитивные (Сложение) + - Слева направо
  Сдвиг << >> Слева направо
  Отношения, проверка типов < > <= >= is as Слева направо
  Эквивалентность ==!= Слева направо
  Логическое & Слева направо
  Логическое исключающее ИЛИ (XOR) ^ Слева направо
  Логическое ИЛИ (OR) | Слева направо
  Условное И && Слева направо
  Условное ИЛИ || Слева направо
  Условное выражение ?: Справа налево
  Присваивание = *= /= %= += -= <<= >>= &= ^= |= Справа налево

Перегрузка операций

Под перегрузкой операции понимается существование нескольких реализаций одной и той же операции. Большинство операций языка C# перегружены - одна и та же операция может применяться к операндам различных типов. Поэтому перед выполнением операции идет поиск реализации, подходящей для данных типов операндов. Замечу, что операции, как правило, выполняются над операндами одного типа. Если же операнды разных типов, то предварительно происходит неявное преобразование типа операнда. Оба операнда могут быть одного типа, но преобразование типов может все равно происходить - по той причине, что для заданных типов нет соответствующей перегруженной операции. Такая ситуация достаточно часто возникает на практике, поскольку, например, операция сложения не определена для младших подтипов арифметического типа. Приведу начальный фрагмент процедуры Express, предназначенной для анализа выражений:

/// <summary>/// Анализ выражений/// </summary>public void Express(){ //перегрузка операций byte b1 =1, b2 =2, b3; short sh1; int in1; //b3 = b1 + b2; //ошибка: результат типа int b3 = (byte)(b1+b2); //sh1 = b1 + b2; //ошибка: результат типа int sh1 = (short)(b1+b2); in1 = b1+ b2 + sh1; Console.WriteLine("b3= " + b3 + " sh1= "+ sh1 +" in1= " + in1);}//Express

Разберем этот фрагмент. Начнем с первого закомментированного оператора присваивания b3 = b1+b2;. Выражение здесь простейшее, включает одну бинарную операцию сложения. Оба операнда имеют тип byte, казалось бы, и результат должен быть типа byte и без помех присвоен переменной b3. Однако это не так. Для данных типа byte нет перегруженной реализации сложения. Ближайшей операцией является сложение целых типа int. Поэтому оба операнда преобразуются к типу int, выполняется операция сложения, результат имеет тип int и не может быть неявно преобразован в тип byte, - возникает ошибка еще на этапе компиляции. Корректная запись показана в следующем операторе. Аналогичная ситуация возникает, когда в левой части оператора стоит переменная типа short, - и здесь необходимо явное приведение к типу. Этого приведения не требуется, когда в левой части стоит переменная типа int.

Давайте разберем, как в данном примере организован вывод в методе WriteLine. До сих пор при вызове метода задавалось несколько параметров и использовалась форма вывода данных с подстановкой значений параметров в строку, заданную первым параметром. Здесь же есть только один параметр - это строка, заданная сложным выражением. Операция, многократно применяемая в этом выражении, это сложение " + ". Операнды сложения имеют разный тип: левый операнд имеет тип string, правый - арифметический (byte, short, int). В этом случае арифметический тип преобразуется к типу string и выполняется сложение строк (конкатенация). Напомню, при преобразовании арифметического типа к типу string вызывается метод ToString(), определенный для всех встроенных типов. Результатом этого выражения является строка, она и будет результатом вывода метода WriteLine.

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







Живите по правилу: МАЛО ЛИ ЧТО НА СВЕТЕ СУЩЕСТВУЕТ? Я неслучайно подчеркиваю, что место в голове ограничено, а информации вокруг много, и что ваше право...

ЧТО ПРОИСХОДИТ, КОГДА МЫ ССОРИМСЯ Не понимая различий, существующих между мужчинами и женщинами, очень легко довести дело до ссоры...

Конфликты в семейной жизни. Как это изменить? Редкий брак и взаимоотношения существуют без конфликтов и напряженности. Через это проходят все...

ЧТО И КАК ПИСАЛИ О МОДЕ В ЖУРНАЛАХ НАЧАЛА XX ВЕКА Первый номер журнала «Аполлон» за 1909 г. начинался, по сути, с программного заявления редакции журнала...





Не нашли то, что искали? Воспользуйтесь поиском гугл на сайте:


©2015- 2024 zdamsam.ru Размещенные материалы защищены законодательством РФ.