ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 11.12.2025
Просмотров: 3264
Скачиваний: 1
В этом случае С# вычисляет ЛогическоеВыражение1 и ЛогическоеВыражение2,
а затем смотрит, равны они оба t r u e или нет, чтобы найти, какое значение следует при своить переменной Ь. Но может оказаться, что С# выполняет лишнюю работу — ведь если одно из выражений равно f a l s e , то каким бы ни было второе, результат не может быть t r u e в любом случае.
Оператор && позволяет избежать вычисления второго выражения, если после вычисле ния первого конечный результат становится очевиден:
b o o l Ь |
= (ЛогическоеВыражение1) |
&& (ЛогическоеВыражение2); |
В этой |
ситуации С# вычисляет значение |
ЛогическоеВыражение1, и если оно равно |
f a l s e , то переменной Ь присваивается значение f a l s e и ЛогическоеВыражение2 не
вычисляется. Если же ЛогическоеВыражение1 |
равно t r u e , то С# вычисляет Логиче- |
|
скоеВыражение2 и после этого определяет, какое значение присвоить переменной Ь. |
||
Оператор |
| | работает аналогично, как видно из следующего выражения: |
|
b o o l b = |
(ЛогическоеВыражение1) |
(ЛогическоеВыражение2); |
В этой ситуации С# вычисляет значение ЛогическоеВыражение1, и если оно равно t r u e , то переменной b присваивается значение t r u e и ЛогическоеВыражение2 не вычисляет ся. Если же ЛогическоеВыражение1 равно f a l s e , то С# вычисляет ЛогическоеВыражение2 и после этого определяет, какое значение присвоить переменной Ь.
Вы можете называть эти операторы "сокращенным и" и "сокращенным или".
В вычислениях тип результата важен не менее, чем сам результат. Рассмотрим сле дующее выражение:
int П ;
П = 5 * 5 + 7;
Калькулятор утверждает, что результат вычислений равен 32. Но это выражение име ет не только значение, но и тип.
Будучи записано на "языке типов", оно принимает следующий вид: int [=] int * int + int;
Для выяснения типа выражения нужно следовать тому же шаблону, что и при вычис лении его значения. Умножение имеет более высокий приоритет, чем сложение. Умно жение int на int дает int. Далее идет сложение int и int, что в результате тоже да ет int. Итак, вычисление типа приведенного выражения происходит таким образом:
int * int + int int + int
int
В ы ч и с л е н и е т и п а о п е р а ц и и
Выяснение типа выражения происходит в нисходящем направлении посредством вы яснения типов подвыражений. Каждое выражение имеет тип, и типы левых и правых ар гументов оператора должны соответствовать самому оператору:
t y p e l <ор> t y p e 2 •=> t y p e 3
(Здесь стрелка означает "дает".) Типы t y p e l и t y p e 2 должны быть совместимы с опе ратором ор.
80 |
Часть II. Основы программирования в С# |
Большинство операторов могут иметь несколько вариантов. Например, оператор ум ножения может быть следующих видов:
int |
* |
i n t |
uint |
* u i n t |
|
long |
* l o n g |
|
float |
* f l o a t |
|
decimal |
* |
decima l |
double |
* |
doubl e |
Таким образом, 2*3 int 6.
•=> i n t
<=> u i n t •=> l o n g •=> f l o a t
<=> d e c i m a l doubl e
использует i n t * i n t версию оператора * и дает в результате
Неявное преобразование типов
Все хорошо, просто и понятно, если умножать две переменные типа i n t или две пе ременные типа f l o a t . Но что получится, если типы аргументов слева и справа будут различны? Что, например, произойдет в следующей ситуации:
int nl = 10 ; double d2 = 5 . 0 ;
double dResul t = nl * d2 ;
Во-первых, в C# нет оператора умножения i n t * d o u b l e . C# может просто сгенери ровать сообщение об ошибке и предоставить разбираться с проблемой программисту. Однако он пытается понять намерения программиста и помочь ему. У С# есть операторы умножения i n t * i n t и double*double . С# мог бы преобразовать d2 в значение i n t , но такое преобразование привело бы к потере дробной части числа (цифр после десятич ной точки). Поэтому вместо этого С# преобразует nl в значение типа doubl e и исполь зует оператор умножения double*double . Это действие известно как неявное повы шение типа (implicit promotion).
Такое повышение называется неявным, поскольку С# выполняет его автоматически, и является повышением, так как включает естественную концепцию высоты типа. Список
операторов умножения был приведен в порядке повышения— от i n t до double, или от int до decima l — от типа меньшего размера к типу большего размера. Между ти пами с плавающей точкой и d e c i m a l неявное преобразование не выполняется. Преоб разование из более емкого типа, такого как double, в менее емкий, такой как i n t , на зывается понижением (demotion).
Повышение иногда называют преобразованием вверх (up conversion), а понижение —
преобразованием вниз (down conversion).
Неявные понижения запрещены. В таких случаях С# генерирует сообщение об ошибке.
Явное преобразование типа
Но что, если С# ошибается? Если на самом деле программист хотел выполнить целое умножение?
Вы можете изменить тип любой переменной с типом-значением с помощью оператора приведения типа (cast), который представляет собой требуемый тип, заключенный в скобки,
и располагаемый непосредственно перед приводимой переменной или выражением.
Глава 4. Операторы |
81 |
Таким образом, в следующем выражении используется оператор умножения i n t * i n t :
i n t n l |
= 1 0 |
; |
d o u b l e |
d2 = |
5 . 0 ; |
d o u b l e n R e s u l t = n l * ( i n t ) d 2 ;
Приведение d2 к типу i n t известно как явное понижение (explicit demotion) или noi нижающее приведение (downcast). Понижение является явным, поскольку программю! явно объявил о своих намерениях.
Вы можете осуществить приведение между двумя любыми типами-значениями, нем висимо от их взаимной высоты.
Избегайте неявного преобразования типов. Делайте все изменения типов! значений явными с помощью оператора приведения.
Оставьте логику в покое
С# не позволяет преобразовывать другие типы в тип b o o l или выполнять преобразо вание типа b o o l в другие типы.
Т и п ы при присваивании
Все сказанное о типах выражений применимо и к оператору присваивания.
Случайные несоответствия типов, приводящие к генерации сообщений об ошибках, обычно происходят в операторах присваивания, а не в точке действи тельного несоответствия.
Рассмотрим следующий пример умножения:
i n t |
n l = 1 0 ; |
i n t |
П2 = 5 . 0 * n l ; |
Вторая строка этого примера приведет к генерации сообщения об ошибке, связанной с несоответствием типов, но ошибка произошла при присваивании, а не при умножении. Вот что произошло: для того чтобы выполнить умножение, С# неявно преобразовал nl в тип d o u b l e . Затем С# выполнил умножение двух значений типа d o u b l e , получив в результате значение того же типа d o u b l e .
Типы левого и правого аргументов оператора присваивания должны совпадать, но тип левого аргумента не может быть изменен. Поскольку С# не может неявно понизить тип выражения, компилятор генерирует сообщение о том, что он не может неявно пре образовать тип d o u b l e в i n t .
При использовании явного приведения никаких проблем не возникнет:
i n t n l = 1 0 ;
i n t n2 = ( i n t ) ( 5 . 0 * n l ) ;
(Скобки необходимы, потому что оператор приведения имеет очень высокий приоритет.) Такой исходный текст вполне работоспособен, так как явное понижение разрешено. Здесь значение nl будет повышено до d o u b l e , выполнено умножение, а результат типа d o u b l e будет понижен до i n t . Однако в этой ситуации надо подумать о душевном здо ровье программиста, поскольку написать просто 5*п1 было бы проще как для програм миста, так и для С#.
82 |
Часть II. Основы программирования в С# |
Большинство операторов имеют два аргумента, меньшинство —- один. И только один оператор — тернарный — имеет три аргумента. Лично я считаю, что это ненужная экзо тика. Вот формат этого оператора:
Выражение типа boo l ? Выражение1 : Выражение2
А это пример его применения: int а = 1;
int Ь = 2 ;
int nMax = (a>b) ? а : Ь;
Если а больше Ь (условие в скобках), значение выражения равно а. Если а не больше Ь, значение выражения равно Ь.
Выражения 1 и 2 могут быть любой сложности, но это должны быть истинные выра жения— они не могут содержать объявлений или других инструкций, не являющихся выражениями.
Тернарный оператор непопулярен3 по следующим причинам.
Он не является необходимым. Использование оператора if, описанного в гла ве 5, "Управление потоком выполнения", дает тот же эффект, и его легче понять.
На тернарный оператор накладываются дополнительные ограничения. На пример, выражения 1 и 2 должны быть одного и того же типа. Это приводит к следующему:
in t |
а = |
1 ; |
double b = 0 . 0 ; |
||
in t |
nMax |
= (a>b) ? а : b; |
Такой исходный текст не будет компилироваться, несмотря на то что в конечном итоге nMax будет иметь значение а. Поскольку а и b должны быть одного и того же типа, а будет повышено до double, чтобы соответствовать Ь. Тип результи
рующего значения оператора |
?: |
оказывается double, и этот тип должен быть |
|||
понижен до i n t перед присваиванием: |
|||||
in t |
а = |
1 ; |
|
|
|
double b |
= 0 . 0 ; |
|
|
|
|
i n t |
nMax; |
|
|
|
|
// |
Можно поступить |
так: |
|
|
|
nMax = |
( i n t ) ( (a>b) |
? а |
: |
b) ; |
|
//. . . или так:
nMax = (a>b) ? а : ( i n t ) b ;
Увидеть тернарный оператор в реальной программе — большая редкость.
3 Непопулярность этого оператора относится к С#, программистами на С и С++ он употребля ется достаточно часто и не вызывает никаких отрицательных эмоций. — Примеч. ред.
Глава 4. Операторы |
83 |
Глава 5
Управление потоком выполнения
>Что делать, если...
>Цикл w h i l e
>Цикл for
>Конструкция s w i t c h
ассмотрим следующую простую программу: |
|
|
|||
using System; |
|
|
|
|
|
namespace |
HelloWorl d |
|
|
|
|
( |
|
|
|
|
|
public |
c l a s s Program |
|
|
|
|
{ |
|
|
|
|
|
// |
Стартовая точка |
программы |
|
|
|
s t a t i c |
v o i d M a i n ( s t r i n g [ ] args ) |
|
|
||
{ |
|
|
|
|
|
|
// |
Приглашение |
для ввода имени |
|
|
|
C o n s o l e . W r i t e L i n e ( " В в е д и т е |
ваше |
и м я : " ) ; |
||
|
// |
Считывание |
введенного имени |
|
|
|
s t r i n g sName = |
C o n s o l e . R e a d L i n e ( ) ; |
|||
|
// |
Приветствие |
с использованием |
введенного имени |
|
|
C o n s o l e . W r i t e L i n e ( " П р и в е т , |
" + sName); |
|||
|
// |
Ожидание подтверждения |
пользователя |
||
|
Console . WriteLine("Нажмит е <Enter> для " |
||||
|
|
|
"завершения |
программы ... ") ; |
|
|
C o n s o l e . R e a d ( ) ; |
|
|
||
Толку от этой программы, помимо иллюстрации некоторых фундаментальных мо ментов программирования С#, очень мало. Она просто возвращает вам то, что вы ввели. Вы можете представить более сложный пример программы, в которой выполняются не которые вычисления над введенными данными и генерируется какой-то более сложный вывод на экран (иначе для чего проводить вычисления?...), но и эта программа будет очень ограничена в своей функциональности.
Одним из ключевых элементов любого компьютерного процессора является его воз можность принимать решения. Под выражением "принимать решения" имеется в виду, ! что процессор может пустить поток выполнения команд по одному или другому пути