Прочитав эту главу, вы научитесь:
• разбираться в инструкциях, идентификаторах и ключевых словах;
• использовать переменные для хранения информации;
• работать с простыми типами данных;
• использовать арифметические операторы, такие как знаки «плюс» (+) и «минус» (–);
• увеличивать и уменьшать значения переменных.
В главе 1 «Добро пожаловать в C#» были рассмотрены вопросы использования среды программирования Microsoft Visual Studio 2015 для создания и запуска консольных программ и графических приложений. В данной главе будут представлены элементы синтаксиса и семантики Microsoft Visual C#, включая инструкции, ключевые слова и идентификаторы. Вы научитесь использовать простые типы данных, встроенные в язык C#, и разбираться в характеристиках значений, содержащихся в каждом типе. Вы также увидите, как объявляются и используются локальные переменные (которые существуют только внутри метода или другого небольшого раздела кода), узнаете о предоставляемых C# арифметических операторах, научитесь пользоваться операторами для работы со значениями и узнаете, как работать с выражениями, содержащими два и более оператора.
Инструкция представляет собой команду, выполняющую какое-либо действие, например вычисление значения и сохранение результата или вывод сообщения на экран пользователя. Инструкции объединяются для создания методов. Более подробно методы рассматриваются в главе 3 «Создание методов и применение областей видимости», а пока представим себе, что методы являются поименованными последовательностями инструкций. Примером метода может служить main, представленный в предыдущей главе.
Инструкции в C# придерживаются четко определенного набора правил, описывающих их формат и конструкцию. Совокупность этих правил называется синтаксисом (в отличие от семантики, являющейся совокупностью описаний действий этих инструкций). Одно из самых простых и наиболее важных правил синтаксиса C# гласит, что все инструкции должны заканчиваться точкой с запятой. Например, в главе 1 было показано, что без закрывающей точки с запятой следующая инструкция компиляцию не пройдет:
Console.WriteLine("Hello, World!");
СОВЕТ C# считается языком свободного формата, а это значит, что пробельные символы, такие как символы пробела или новой строки, не имеют значения, если только не применяются в качестве разделителей. Иными словами, вы вправе размечать свои инструкции в любом удобном стиле. Но чтобы ваши программы легче читались и в них было проще разобраться, лучше придерживаться простого постоянного стиля разметки.
Успех программирования на любом языке обусловливается изучением его синтаксиса и семантики с последующим использованием языка естественным, характерным для него образом. Такой подход упростит сопровождение ваших программ. По мере изучения материала данной книги вы увидите примеры использования наиболее важных инструкций C#.
Идентификаторами называются имена, используемые вами для идентификации элементов в своих программах, например пространств имен, классов, методов и переменных. (Что такое переменные, вы скоро узнаете.) При выборе идентификаторов в C# нужно придерживаться следующих синтаксических правил.
• Разрешается использовать только буквы (в верхнем или в нижнем регистре), цифры и символы подчеркивания.
• Идентификаторы должны начинаться с буквы или символа подчеркивания.
Например, result, _score, footballTeam и plan9 считаются допустимыми идентификаторами, а result%, footballTeam$ и 9plan не допускаются.
ВНИМАНИЕ C# относится к языкам, чувствительным к регистру символов: footballTeam и FootballTeam — это два разных идентификатора.
В C# для внутреннего потребления зарезервировано 77 идентификаторов, которые вам нельзя использовать для своих нужд. Эти идентификаторы называются ключевыми словами, и у каждого из них имеется конкретное назначение. К примерам ключевых слов относятся class, namespace и using. По мере чтения книги вы изучите большинство ключевых слов C#. Перечень ключевых слов выглядит следующим образом.
abstract | do | In | protected | true |
as | double | Int | public | try |
base | else | interface | readonly | typeof |
bool | enum | internal | ref | uint |
break | event | Is | return | ulong |
byte | explicit | lock | sbyte | unchecked |
case | extern | long | sealed | unsafe |
catch | false | namespace | short | ushort |
char | finally | new | sizeof | using |
checked | fixed | null | stackalloc | virtual |
class | float | object | static | void |
const | for | operator | string | volatile |
continue | foreach | Out | struct | while |
decimal | goto | override | switch |
|
default | if | params | this |
|
delegate | implicit | private | throw |
|
СОВЕТ В окне редактора Visual Studio 2015 набранные ключевые слова выделяются синим цветом.
В C# используются также идентификаторы, показанные далее. Они не считаются зарезервированными в C#, следовательно, их можно использовать в качестве идентификаторов своих методов, переменных и классов, но по возможности этого следует избегать.
add | Get | remove |
alias | Global | select |
ascending | Group | set |
async | Into | value |
await | Join | var |
descending | Let | where |
dynamic | orderby | yield |
from | partial |
|
Переменной называется место в памяти, где хранится значение. Переменную можно представить в виде блока в компьютерной памяти, в котором хранится временная информация. Каждой переменной в программе должно быть дано вполне определенное имя, которое уникальным образом ее идентифицирует в используемом контексте. Имя переменной используется для ссылки на содержащееся в этой переменной значение. Например, если нужно сохранить значение стоимости товара в магазине, можно создать переменную с простым именем cost и сохранить в ней стоимость товара.
После этого при ссылке на переменную cost извлекаемым значением будет сохраненная ранее стоимость товара.
Во избежание путаницы с определяемыми вами переменными нужно придерживаться соглашения о порядке присваивания имен переменным. Особую важность это приобретает, если вы являетесь частью команды, состоящей из нескольких разработчиков, работающих над различными компонентами приложения, где строгое соглашение о присваивании имен помогает избежать путаницы и сократить поле допущения ошибок. Основные рекомендации изложены в следующем перечне.
• Не начинайте идентификатор со знака подчеркивания. Хотя это и допускается в C#, у вас могут возникнуть ограничения во взаимодействии вашего кода с приложениями, созданными на других языках, например на Microsoft Visual Basic.
• Не создавайте идентификаторы, отличающиеся друг от друга только регистром символов. Например, не создавайте для одновременного использования одну переменную с именем myVariable, а другую — с именем MyVariable, потому что их легко перепутать. Кроме того, определение переменных, отличающихся друг от друга только регистром символов, ограничивает возможность повторного использования классов в приложениях, разработанных с помощью других языков, нечувствительных к регистру символов, таких, к примеру, как Visual Basic.
• Начинайте имя с буквы в нижнем регистре.
• В идентификаторе, состоящем из нескольких слов, начинайте второе и каждое последующее слово с буквы в верхнем регистре. (Такая форма записи называется смешанным регистром, или, по-английски, — camelCase.)
• Не используйте венгерскую нотацию. (Если у вас есть опыт разработки на Microsoft Visual C++, то, скорее всего, венгерская нотация вам знакома. Если же вы не знаете, что это такое, то и нечего забивать голову ненужной информацией!)
Например, score, footballTeam, _score и FootballTeam являются допустимыми именами переменных, но к числу рекомендованных относятся только два первых.
В переменных содержатся значения. В C# имеется множество различных типов значений, которые могут храниться и обрабатываться. Назовем только три из них: целые числа, числа с плавающей точкой и строки символов. При объявлении переменной нужно указать тип содержащихся в ней данных.
Объявление типа и имени переменной производится в инструкции объявления. Например, в следующей инструкции объявляется, что в переменной по имени age содержатся значения типа int (integer). Как всегда, инструкцию нужно завершить точкой с запятой:
int age;
Тип переменной, int, является названием одного из простых типов языка C#, integer, представляющего собой целое число. (Чуть позже в этой главе нам станут известны некоторые другие простые типы данных.)
ПРИМЕЧАНИЕ Если вы программировали на Visual Basic, то, наверное, заметили, что в C# запрещено неявное объявление переменных. Перед использованием все переменные сначала должны быть объявлены.
После объявления переменной ей можно присвоить значение. Следующая инструкция присваивает переменной age значение 42. Еще раз обратите внимание на обязательность использования точки с запятой:
age = 42;
Знак равенства (=) является оператором присваивания, который присваивает значение, находящееся справа от него, той переменной, которая находится слева от него. После этого присваивания переменную age можно использовать в вашем коде для ссылки на хранящееся в ней значение. Следующая инструкция записывает значение переменной age (42) на консоль:
Console.WriteLine(age);
СОВЕТ Если в окне редактора Visual Studio 2015 указатель мыши установить над переменной, то тип этой переменной будет показан в экранной подсказке (ScreenTip).
В C# имеется ряд встроенных типов, которые называются простыми типами данных. Наиболее распространенные простые типы данных C# и диапазоны их значений перечислены в табл. 2.1.
Таблица 2.1
Тип данных | Описание | Размерность, бит | Диапазон | Пример использования |
int | Целые числа (integers) | 32 | От –231 до 231 – 1 | int count; count = 42; |
long | Целые числа (с расширенным диапазоном) | 64 | От –263 до 263 – 1 | long wait; wait = 42L; |
float | Числа с плавающей точкой | 32 | От –3,4 · 10–38 до 3,4 · 1038 | float away; away = 0.42F; |
double | Числа с плавающей точкой двойной точности | 64 | От ±5,0 · 10–324 до ±1,7 · 10308 | double trouble; trouble = 0.42; |
decimal | Денежные значения | 128 | 28 значащих цифр | decimal coin; coin = 0.42M; |
string | Последовательность символов | По 16 бит на символ | Неприменимо | string vest; vest = "forty two"; |
char | Отдельно взятый символ | 16 | От 0 до 216 – 1 | char grill; grill = 'x'; |
bool | Булево значение | 8 | true или false | bool teeth; teeth = false; |
При объявлении переменной в ней, пока ей не будет присвоено значение, содержится произвольное значение. Это обстоятельство часто становится источником ошибок в программах, написанных на C и C++, где переменная создавалась и случайно использовалась в качестве источника информации еще до того, как ей давалось значение. В C# использование переменных с неприсвоенными значениями недопустимо. Перед тем как воспользоваться переменной, ей нужно присвоить значение, в противном случае ваша программа не будет скомпилирована. Это требование называется правилом определенности переменной. Например, причиной выдачи сообщения об ошибке во время компиляции служат следующие инструкции: "Use of unassigned local variable 'age'" (Использование переменной 'age' с неприсвоенным значением), поскольку инструкция Console.WriteLine пытается вывести на экран значение неинициализированной переменной:
int age;
Console.WriteLine(age); // ошибка в ходе компиляции
В следующем примере для демонстрации порядка работы нескольких простых типов данных используется программа на C# под названием PrimitiveDataTypes.
Выберите в меню Файл среды Visual Studio 2015 пункт Открыть, а затем щелкните на пункте Решение или проект. Появится диалоговое окно Открыть проект. Перейдите в папку \Microsoft Press\VCSBS\Chapter 2\PrimitiveDataTypes, которая находится в вашей папке документов. Выберите файл решения PrimitiveDataTypes, а затем щелкните на кнопке Открыть. Решение загрузится, и в обозревателе решений будет показан проект PrimitiveDataTypes.
ПРИМЕЧАНИЕ Имена файлов решений имеют суффикс .sln, например PrimitiveDataTypes.sln. В решении может содержаться один или несколько проектов. У файлов проектов Visual C# имеется суффикс .csproj. Если открыть проект, а не решение, среда Visual Studio 2015 автоматически создаст для него новый файл решения. Если вы не в курсе данной особенности, это может привести к путанице, поскольку в результате может быть случайно создано сразу несколько решений для одного и того же проекта.
Щелкните в меню Отладка на пункте Начать отладку.
В Visual Studio могут появиться несколько предупреждений, которые можно совершенно свободно проигнорировать. (Соответствующие корректировки будут внесены в следующем упражнении.)
Рис. 2.1
Щелкните в списке Choose A Data Type (Выберите тип данных) (рис. 2.1) на пункте string (Строковое значение). В поле Sample Value (Образец значения) появится текст forty two. Щелкните еще раз в списке Choose A Data Type на пункте int (Целочисленное значение). В поле Sample Value появится значение to do, показывающее, что инструкции для отображения значения типа int еще должны быть написаны. Щелкните на каждом пункте списка типа данных. Убедитесь, что код для типов double и bool еще не создан. Вернитесь в среду Visual Studio 2015, а затем щелкните в меню Отладка на пункте Остановить отладку. Для остановки отладки можно также закрыть окно.
Раскройте в обозревателе решений проект PrimitiveDataTypes, а затем дважды щелкните на имени файла MainPage.xaml. В окне конструктора появится форма для приложения.
СОВЕТ Если ваш экран недостаточно велик для отображения всей формы, можно воспользоваться функцией увеличения и уменьшения, оперируя комбинациями клавиш Ctrl+Alt+= и Ctrl+Alt+- или выбрав размер из раскрывающегося списка Масштаб (Zoom) в левом нижнем углу окна конструктора.
Прокрутите в панели XAML код до того места, где расположена разметка для элемента управления ListBox. В этом элементе отображается перечень типов данных из левой части формы, он имеет следующий вид (ряд свойств из этого текста был изъят):
<ListBox x:Name="type" ... SelectionChanged="typeSelectionChanged">
<ListBoxItem>int</ListBoxItem>
<ListBoxItem>long</ListBoxItem>
<ListBoxItem>float</ListBoxItem>
<ListBoxItem>double</ListBoxItem>
<ListBoxItem>decimal</ListBoxItem>
<ListBoxItem>string</ListBoxItem>
<ListBoxItem>char</ListBoxItem>
<ListBoxItem>bool</ListBoxItem>
</ListBox>
Элемент управления ListBox отображает каждый тип данных в виде отдельного элемента ListBoxItem. Если при работающем приложении пользователь щелкает на элементе списка, происходит событие SelectionChanged (оно немного похоже на показанное в главе 1 событие Click, происходящее, когда пользователь щелкает на кнопке). Можно увидеть, что в таком случае ListBox вызывает метод typeSelectionChanged. Этот метод определен в файле MainPage.xaml.cs.
Щелкните в меню Вид на пункте Код. Откроется окно редактора, в котором будет показан файл MainPage.xaml.cs.
ПРИМЕЧАНИЕ Не забудьте, что для доступа к коду можно также воспользоваться обозревателем решений. Щелкните на стрелке слева от имени файла MainPage.xaml, чтобы раскрылся узел, а затем дважды щелкните на имени файла MainPage.xaml.cs.
Найдите в окне редактора метод typeSelectionChanged.
ПРИМЕЧАНИЕ Чтобы найти нужное место в вашем проекте, следует в меню Правка (Edit) щелкнуть на пункте Найти и заменить (Find And Replace), а затем щелкнуть на пункте Быстрый поиск (Quick Find). В правом верхнем углу окна редактора откроется меню. В текстовом поле этого контекстного меню наберите имя искомого объекта, а затем щелкните на кнопке Найти далее (она имеет вид направленной вправо стрелки, расположенной сразу за текстовым полем) (рис. 2.2).
Изначально поиск ведется без учета регистра символов. Если нужно провести поиск с учетом регистра, щелкните на кнопке Учитывать регистр (с изображением букв Aa), расположенной ниже текста, задающего поиск.
Для отображения диалогового окна быстрого поиска вместо использования меню Правка можно также воспользоваться комбинацией клавиш Ctrl+F. А для отображения окна быстрой замены можно воспользоваться комбинацией клавиш Ctrl+H.
Рис. 2.2
В качестве альтернативы использованию функции быстрого поиска установить местонахождение методов в классе можно также с помощью раскрывающегося списка элементов класса, расположенного чуть выше окна редактора справа (рис. 2.3).
Рис. 2.3
Все методы класса вместе с переменными и другими составляющими класса отображаются в поле раскрывающегося списка элементов класса. (Подробнее эти элементы будут рассматриваться в следующих главах.) Щелкните в этом списке на методе typeSelectionChanged, и курсор переместится непосредственно на имеющийся в классе метод typeSelectionChanged.
При наличии опыта программирования на других языках вы могли бы уже догадаться, как работает метод typeSelectionChanged, если же такого опыта у вас нет, разобраться в коде поможет материал главы 4 «Использование инструкций принятия решений». А сейчас вам нужно лишь усвоить, что при щелчке пользователя на составляющей элемента управления ListBox подробности этой составляющей передаются данному методу, который затем использует эту информацию для определения того, что произойдет далее. Например, если пользователь щелкнет на составляющей float, этот метод вызовет другой метод по имени showFloatValue.
Прокрутите код, чтобы найти метод showFloatValue, имеющий следующий вид:
private void showFloatValue()
{
float floatVar;
floatVar = 0.42F;
value.Text = floatVar.ToString();
}
Основу метода составляют три инструкции. Первая инструкция объявляет переменную floatVar, относящуюся к типу float. Вторая инструкция присваивает floatVar значение 0.42F.
ВНИМАНИЕ Буква F представляет собой суффикс типа, указывающий, что 0,42 должно рассматриваться как значение числа с плавающей точкой. Если забыть поставить F, значение 0,42 будет рассматриваться как число с двойной точностью и ваша программа не пройдет компиляцию, поскольку вы не можете присвоить значение одного типа переменной другого типа без написания дополнительного кода, — в этом C# проявляет особую строгость.
Третья инструкция выводит значение этой переменной в поле значений формы. Обратите внимание на эту инструкцию. Как уже было показано в главе 1, способ вывода информации в текстовое поле заключается в установке значения его свойства Text (в главе 1 это было проделано с помощью XAML). Также эту задачу можно решить чисто программными средствами, чем мы здесь и занимаемся. Заметьте, что обращение к свойству объекта происходит с использованием той же системы записи с точкой, которую вы видели при запуске метода. (Помните Console.WriteLine из главы 1?) Кроме этого, данные, помещаемые в свойство Text, должны быть строкой, а не числом. При попытке присвоить свойству Text число ваша программа не пройдет компиляцию. К счастью, .NET Framework предоставляет помощь в виде метода ToString.
У каждого типа данных в .NET Framework имеется метод ToString. Задача метода ToString заключается в преобразовании объекта в его строковое представление. Метод showFloatValue использует метод ToString переменной float объекта floatVar для создания строковой версии значения этой переменной. Затем можно будет без всякого опасения присвоить эту строку свойству Text значения текстового поля. При создании собственных типов данных и классов можно определять свои реализации метода ToString для указания того, как ваш класс должен быть представлен в виде строки. Как создаются собственные классы, вы узнаете в главе 7 «Создание классов и объектов и управление ими».
Найдите в окне редактора метод showIntValue:
private void showIntValue()
{
value.Text = "to do";
}
Этот метод вызывается, когда в списке выбора типа данных делается щелчок на поле int. В начале кода метода showIntValue в новой строке после открывающей фигурной скобки наберите следующие две инструкции, выделенные жирным шрифтом:
private void showIntValue()
{
int intVar;
intVar = 42;
value.Text = "to do";
}
Первая инструкция создает переменную по имени intVar, в которой может содержаться значение типа int. Вторая инструкция присваивает этой переменной значение 42. В исходной инструкции данного метода измените строку "to do" на intVar.ToString();.
Теперь этот метод должен приобрести следующий вид:
private void showIntValue()
{
int intVar;
intVar = 42;
value.Text = intVar.ToString();
}
Щелкните в меню Отладка на пункте Начать отладку. Форма появится еще раз. В списке выбора типа данных выберите тип int. Убедитесь в том, что в текстовом поле Sample Value выводится значение 42. Вернитесь в Visual Studio, а затем щелкните в меню Отладка на пункте Остановить отладку.
Найдите в окне редактора метод showDoubleValue. Отредактируйте этот метод, чтобы он приобрел точно такой же вид, как в следующем коде, и содержал инструкции, выделенные жирным шрифтом:
private void showDoubleValue()
{
double doubleVar;
doubleVar = 0.42;
value.Text = doubleVar.ToString();
}
Этот код похож на код метода showIntValue, за исключением того, что он создает переменную doubleVar, содержащую значение с двойной точностью, и ей присваивается значение 0,42.
Найдите в окне редактора метод showBoolValue. Отредактируйте этот метод, чтобы он приобрел следующий вид:
private void showBoolValue()
{
bool boolVar;
boolVar = false;
value.Text = boolVar.ToString();
}
Этот код также похож на код предыдущего примера, за исключением того, что переменная boolVar может содержать только булево значение, true или false. В данном случае присваиваемым значением является false.
Щелкните в меню Отладка на пункте Начать отладку. В списке выбора типов данных выберите типы float, double и bool. В каждом случае проверьте, что в текстовом поле Sample Value выводится правильное значение.
Вернитесь в Visual Studio, а затем щелкните в меню Отладка на пункте Остановить отладку.
C# поддерживает обычные арифметические операции, известные вам с детства: знак «плюс» (+) для сложения, знак «минус» (–) для вычитания, звездочка (*) для умножения и прямой слеш (/) для деления. Символы +, –, * и / называются операторами, потому что они выполняют операции над значениями для создания новых значений. В следующем примере переменная moneyPaidToConsultant содержит в конечном итоге произведение 750 (дневной ставки) и 20 (количества рабочих дней консультанта):
long moneyPaidToConsultant;
moneyPaidToConsultant = 750 * 20;
ПРИМЕЧАНИЕ Значения, над которыми оператор производит свое действие, называются операндами. В выражении 750 * 20, символ * является оператором, а 750 и 20 — операндами.
Не все операторы применимы ко всем типам данных. Какие именно операторы могут быть применены к значению, зависит от типа значения. Например, все математические операторы можно применять к значениям типа char, int, long, float, double или decimal. Но за исключением оператора, обозначаемого знаком «плюс» (+), арифметические операторы нельзя применять к значениям типа string и никакие из этих операторов нельзя использовать со значениями типа bool. Следовательно, показанная далее инструкция недопустима, поскольку для типа данных string оператор «минус» не поддерживается (вычитание одной строки из другой не имеет никакого смысла):
// ошибка в ходе компиляции
Console.WriteLine("Gillingham" - "Forest Green Rovers");
Но для объединения строковых значений можно использовать оператор +. При этом нужно проявлять осмотрительность, поскольку могут быть получены неожиданные результаты. Например, следующая инструкция выведет на консоль 431 (а не 44):
Console.WriteLine("43" + "1");
СОВЕТ Если нужно выполнить арифметическое вычисление над значениями, содержащимися в виде строк, среда .NET Framework предоставляет метод под названием Int32.Parse, которым можно воспользоваться для преобразования строкового значения в целое число.
В самой последней версии C# появилось новое функциональное свойство, называемое строковой интерполяцией, переводящее многие варианты использования оператора + для объединения строк в разряд устаревших.
Довольно часто объединение строк применяется для создания строковых значений, включающих значения переменных. Пример такого применения вы уже видели при создании графического приложения в главе 1. В метод okClick добавлялась следующая строка кода:
MessageDialog msg = new MessageDialog("Hello " + userName.Text);
Строковая интерполяция позволяет воспользоваться вместо этого следующим синтаксисом:
MessageDialog msg = new MessageDialog($"Hello {userName.Text}");
Символ $ в начале строки показывает, что это интерполируемая строка и что любое выражение между символами { и } должно быть вычислено, а результат должен быть вставлен вместо него. Без лидирующего символа $ строка {username.Text} будет рассматриваться буквально.
Строковая интерполяция более эффективна, чем использование оператора +. (Объединение строк с помощью оператора + с учетом того, каким образом среда .NET Framework обрабатывает строки, может потреблять много памяти.) Строковая интерполяция претендует и на то, что в ней легче разобраться и при ее применении труднее допустить ошибку.
Следует также иметь в виду, что тип результата арифметической операции зависит от типа используемых операндов. Например, значением выражения 5.0/2.0 является 2.5, оба операнда относятся к типу double, следовательно, результат также будет типа double. (В C# числовые литералы с десятичной точкой всегда относятся к типу double, а не к типу float, чтобы их обработка велась с максимально возможной точностью.) Но значение выражения 5/2 равно 2. В этом случае оба операнда принадлежат к типу int, следовательно, результат также принадлежит к типу int.
В подобных ситуациях C# всегда производит округление в сторону нуля. При смешивании типов операндов ситуация немного усложняется. Например, выражение 5/2.0 состоит из типов данных int и double. Компилятор C# обнаруживает несоответствие и создает код, преобразующий int в double до выполнения операции. Поэтому результатом операции является значение типа double (2.5). Но несмотря на то что этот код работает, подобное смешивание типов считается порочной практикой.
C# также поддерживает менее известный арифметический оператор — извлечение остатка целочисленного деления, который представлен знаком процента (%). Результатом x % y является остаток после деления значения x на значение y. Следовательно, 9 % 2, к примеру, дает результат 1, поскольку, если 9 разделить на 2, то получится 4, а остаток будет равен 1.
ПРИМЕЧАНИЕ Если вам знаком язык C или C++, то вы знаете, что использовать в этих языках оператор извлечения остатка от деления в отношении значения типов float или double невозможно. Но в C# это правило смягчено. Оператор извлечения остатка от деления можно применять с числовыми значениями любых типов, и результат не обязательно должен быть целым числом. Например, результат выражения 7.0 % 2.4 равен 2.2.
В C# имеется еще ряд относящихся к числам особенностей, о которых вам следует знать. Например, результатом деления любого числа на нуль является бесконечность, что выходит за рамки определения типов int, long и decimal, следовательно, вычисление такого выражения, как 5/0, приводит к возникновению ошибки. Но у типов double и float имеется специальное значение, которое может представлять бесконечность, и значением выражения 5.0/0.0 будет Infinity. В этом правиле есть одно исключение — значение выражения 0.0/0.0. Обычно при делении нуля на какое-нибудь число получается нулевой результат, но при делении любого числа на нуль получается бесконечность. Выражение 0.0/0.0 приводит к парадоксу — значение должно быть нулем и бесконечностью одновременно. Для данной ситуации в C# имеется еще одно специальное значение, которое называется NaN и означает not a number (не число). Следовательно, при вычислении выражения 0.0/0.0 результат будет иметь значение NaN.
Значения NaN и Infinity распространяются и на выражения. Если вычисляется выражение 10 + NaN, результатом будет NaN, а если вычисляется выражение 10 + Infinity, результатом будет Infinity. Результатом вычисления выражения Infinity * 0 будет NaN.
В следующем примере показан способ использования арифметических операторов в отношении значений типа int.
Откройте в Visual Studio 2015 проект MathsOperators, который находится в папке \Microsoft Press\VCSBS\Chapter 2\MathsOperators вашей папки документов.
Щелкните в меню Отладка на пункте Начать отладку. Появится следующая форма (рис. 2.4).
Наберите в поле Left Operand (Левый операнд) число 54, а в поле Right Operand (Правый операнд) — число 13. Теперь к значениям в текстовых полях можно применить любой оператор. Щелкните на варианте - Subtraction (Вычитание), а затем на кнопке Calculate (Вычислить). Текст в поле Expression (Выражение) изменится на 54 – 13, но в поле Result (Результат) появится 0, что, несомненно, неправильно.
Щелкните на варианте / Division (Деление), а затем на кнопке Calculate. Текст в поле Expression изменится на 54/13, и в поле Result опять появится 0.
Щелкните на варианте / Remainder (Получение остатка от деления), а затем на кнопке Calculate. Текст в поле Expression изменится на 54%13, а в поле Result опять
Рис. 2.4
появится 0. Проверьте другие комбинации чисел и операторов, и вы увидите, что все они на данный момент при вычислении приводят к появлению значения 0.
ПРИМЕЧАНИЕ Если в любое из полей операндов ввести нецелочисленное значение, приложение обнаружит ошибку и выведет на экран сообщение о том, что введенная строка имеет неверный формат (Input string was not in a correct format). Дополнительные сведения о перехвате ошибок и их обработке, а также об исключениях будут даны в главе 6 «Обработка ошибок и исключений».
Завершив перечисленные действия, вернитесь в Visual Studio, а затем щелкните в меню Отладка на пункте Остановить отладку.
Как вы уже могли догадаться, пока никакие вычисления в приложении MathsOperators не реализованы. Этот недостаток будет исправлен в следующем упражнении.
Выведите в окно конструктора форму MainPage.xaml (дважды щелкните на имени файла MainPage.xaml, указанного в обозревателе решений в проекте MathsOperators). В меню Вид выберите пункт Другие окна (Other Windows), после чего щелкните на пункте Структура документа (Document Outline).
Появится окно Структура документа, в котором будут показаны имена и типы имеющихся в форме элементов управления. Это окно обеспечивает простой способ поиска и выбора элементов управления в сложной форме. Эти элементы управления выстроены в определенной иерархии, начиная с элемента Page, составляющего форму. Как упоминалось в главе 1, страница приложения универсальной платформы Windows (Universal Windows Platform (UWP)) содержит элемент управления Grid и другие элементы, помещенные внутрь этого Grid-элемента. Если в окне структуры документа раскрыть узел Grid, появятся другие элементы управления, которые начнутся с еще одного элемента Grid (внешний Grid выступает в роли структуры, а внутренний Grid содержит элементы управления, которые вы видите в форме). Если раскрыть внутренний Grid-элемент, вы увидите каждый элемент управления формы (рис. 2.5).
Рис. 2.5
Если щелкнуть на любом из этих элементов управления, в окне конструктора будет выделен соответствующий ему элемент. Сообразно этому, если выбрать элемент управления в окне конструктора, соответствующий элемент будет выбран в окне структуры документа. (Чтобы посмотреть на это в действии, закрепите окно структуры документа на месте, отменив выбор режима скрытия окна, щелкнув для этого на кнопке Автоматически скрывать (Auto Hide) в правом верхнем углу окна структуры документа.)
Щелкните в форме на двух элементах управления типа TextBox, в которых пользователь набирает числа. Проверьте в окне структуры документа, что они носят названия lhsOperand и rhsOperand. При запуске формы в свойстве Text каждого из этих элементов управления содержатся значения, введенные пользователем.
В нижней части формы проверьте, что элемент управления типа TextBlock, используемый для вывода вычисляемого значения, называется expression и что элемент управления типа TextBlock, используемый для отображения результата вычисления, называется result.
Закройте окно структуры документа. Щелкните в меню Вид на пункте Код, чтобы в окне редактора отобразился код файла MainPage.xaml.cs.
Найдите в редакторе метод addValues. Он имеет следующий вид:
private void addValues()
{
int lhs = int.Parse(lhsOperand.Text);
int rhs = int.Parse(rhsOperand.Text);
int outcome = 0;
// TODO: Add rhs to lhs and store the result in outcome
expression.Text = $"{lhsOperand.Text} + {rhsOperand.Text}";
result.Text = outcome.ToString();
}
Первая инструкция в этом методе объявляет переменную типа int по имени lhs и инициализирует ее с использованием целого числа, соответствующего значению, набранному пользователем в поле lhsOperand. Вспомним, что свойство Text элемента управления типа TextBox содержит строку, но переменная lhs относится к типу int, поэтому, прежде чем присваивать значение переменной lhs, вы должны преобразовать эту строку в целое число. Тип данных int предоставляет метод int.Parse, который именно этим и занимается.
Вторая инструкция объявляет переменную типа int по имени rhs и инициализирует ее значением, находящимся в поле rhsOperand, после преобразования этого значения в int.
Третья инструкция объявляет переменную типа int по имени outcome.
Далее следует строка комментария, в которой сообщается о том, что вам нужно сложить rhs и lhs и сохранить результат в outcome. Этот фрагмент кода здесь не представлен, и вам нужно его создать, чем мы вскоре и займемся.
Пятая инструкция использует строковую интерполяцию, показывающую, что вычисление было выполнено, и присваивает результат свойству expression.Text, что приводит к появлению строки в поле Expression этой формы.
Последняя инструкция выводит результат вычисления, присваивая его свойству Text поля Result. Следует помнить, что свойство Text содержит значение типа string, а результат вычисления содержит значение типа int, поэтому, прежде чем присваивать результат свойству Text, значение тип int нужно преобразовать в string. Именно этим и занимается метод ToString, принадлежащий типу int.
Добавьте ниже комментария в середине метода addValues следующую инструкцию, выделенную жирным шрифтом:
private void addValues()
{
int lhs = int.Parse(lhsOperand.Text);
int rhs = int.Parse(rhsOperand.Text);
int outcome = 0;
// TODO: Add rhs to lhs and store the result in outcome
outcome = lhs + rhs;
expression.Text = $"{lhsOperand.Text} + {rhsOperand.Text}";
result.Text = outcome.ToString();
}
Эта инструкция вычисляет выражение lhs + rhs и сохраняет результат в переменной outcome.
Исследуйте содержимое метода subtractValues. Вы увидите, что он соответствует тому же самому шаблону. В него нужно добавить инструкцию для вычисления результата вычитания rhs из lhs и его сохранения в outcome. Добавьте к методу следующую инструкцию, выделенную жирным шрифтом:
private void subtractValues()
{
int lhs = int.Parse(lhsOperand.Text);
int rhs = int.Parse(rhsOperand.Text);
int outcome = 0;
// TODO: Subtract rhs from lhs and store the result in outcome
outcome = lhs - rhs;
expression.Text = $"{lhsOperand.Text} - {rhsOperand.Text}";
result.Text = outcome.ToString();
}
Исследуйте содержимое методов multiplyValues, divideValues и remainderValues. В них точно так же не хватает важной инструкции, выполняющей вычисление. Добавите соответствующие инструкции, выделенные жирным шрифтом:
private void multiplyValues()
{
int lhs = int.Parse(lhsOperand.Text);
int rhs = int.Parse(rhsOperand.Text);
int outcome = 0;
// TODO: Multiply lhs by rhs and store the result in outcome
outcome = lhs * rhs;
expression.Text = $"{lhsOperand.Text} * {rhsOperand.Text}";
result.Text = outcome.ToString();
}
private void divideValues()
{
int lhs = int.Parse(lhsOperand.Text);
int rhs = int.Parse(rhsOperand.Text);
int outcome = 0;
// TODO: Divide lhs by rhs and store the result in outcome
outcome = lhs / rhs;
expression.Text = $"{lhsOperand.Text} / {rhsOperand.Text}";
result.Text = outcome.ToString();
}
private void remainderValues()
{
int lhs = int.Parse(lhsOperand.Text);
int rhs = int.Parse(rhsOperand.Text);
int outcome = 0;
// TODO: Work out the remainder after dividing lhs by rhs and store the
// result in outcome
outcome = lhs % rhs;
expression.Text = $"{lhsOperand.Text} % {rhsOperand.Text}";
result.Text = outcome.ToString();
}
Щелкните в меню Отладка на пункте Начать отладку, чтобы произвести сборку и запуск приложения.
Наберите 54 в поле Left Operand и 13 — в поле Right Operand, щелкните на варианте + Addition, а затем на кнопке Calculate. В поле Result должно появиться значение 67.
Щелкните на варианте – Subtraction, а затем на кнопке Calculate. В поле Result должно появиться значение 41.
Щелкните на варианте * Multiplication, а затем на кнопке Calculate. Убедитесь в том, что теперь в поле Result появилось значение 702.
Щелкните на варианте / Division, а затем на кнопке Calculate. Убедитесь в том, что теперь в поле Result появилось значение 4. В реальности 54/13 равно 4,153846 в периоде, но это не реальность, это язык C#, выполняющий целочисленное деление. Как уже говорилось, при делении одного целого числа на другое ответ должен быть возвращен в виде целого числа.
Щелкните на варианте % Remainder, а затем на кнопке Calculate. Убедитесь в том, что теперь показано значение 2. При работе с целыми числами остаток от деления 54 на 13 равен 2: (54 – ((54/13) · 13)) = 2. Дело в том, что вычисление на каждой стадии округляется вниз до целого числа. (Мой учитель математики в средней школе схватился бы за голову, если бы ему сказали, что (54/13) · 13 не равно 54!)
Вернитесь в Visual Studio и остановите отладку.
Очередность определяет порядок, в котором в выражении происходит вычисление с участием тех или иных операторов. Рассмотрим следующее выражение, использующее операторы + и *:
2 + 3 * 4
Это выражение содержит потенциальную неопределенность: что выполняется в первую очередь, сложение или умножение? Порядок выполнения операций играет важную роль, поскольку он изменяет результат.
• Если сначала выполняется сложение, а за ним умножение, результат сложения (2 + 3) формирует левый операнд оператора * и результатом всего выражения становится 5 ·4, что равно 20.
• Если сначала выполняется умножение, а за ним сложение, результат умножения (3 · 4) формирует правый операнд оператора + и результатом всего выражения становится 2 + 12, что равно 14.
В C# мультипликативные операторы (*, / и %) имеют приоритет над аддитивными операторами (+ и –), следовательно, в таком выражении, как 2 + 3 × 4, сначала выполняется умножение, а затем сложение. Поэтому ответ вычисления 2 + 3 × 4 равен 14.
Для изменения очередности и принуждения операндов к иной привязке к операторам можно воспользоваться круглыми скобками. Например, в следующем выражении круглые скобки заставляют 2 и 3 быть привязанными к оператору + (выдавая результат 5) и результат сложения формирует левый операнд для оператора *, чтобы получилось значение 20:
(2 + 3) * 4
ПРИМЕЧАНИЕ Под круглыми скобками понимается пара символов (). Под фигурными скобками понимается пара символов { }. А под квадратными скобками понимается пара символов [ ].
Приоритетность операторов — всего лишь половина истории. Давайте подумаем: что происходит, когда выражение содержит различные операторы, имеющие одинаковый уровень приоритета? Тут на первый план выступает ассоциативность, выражающаяся в направлении (левом или правом), в котором вычисляются операнды операторов. Рассмотрим следующее выражение, в котором используются операторы / и *:
4 / 2 * 6
На первый взгляд в этом выражении присутствует потенциальная неоднозначность. Что выполняется первым, деление или умножение? Уровень приоритета у обоих операторов одинаковый (они оба относятся к мультипликативным операторам), но порядок их применения в выражении играет важную роль, поскольку вы можете получить два разных результата.
• Если сначала выполняется деление, результат этого деления (4/2) формирует операнд оператора *, а результатом всего выражения будет (4/2) × 6, или 12.
• Если сначала выполняется умножение, результат этого умножения (2 × 6) формирует операнд оператора /, а результатом всего выражения будет 4/(2 × 6), или 4/12.
В данном случае порядок вычисления определяется ассоциативностью операторов. Оба оператора, * и /, обладают левой ассоциативностью, что означает, что эти операнды вычисляются слева направо. В данном случае 4/2 будет вычислено до умножения на 6, что даст результат 12.
В C# знак равенства (=) является оператором. Все операторы возвращают значение на основе своих операндов. Оператор присваивания = исключением не является. Он получает два операнда: операнд справа от него вычисляется, а затем сохраняется в операнде, расположенном слева от него. Значением оператора присваивания является значение, присвоенное левому операнду. Например, в следующей инструкции присваивания значение, возвращаемое оператором присваивания, равно 10, и оно же является значением, присваиваемым переменной myInt:
int myInt;
myInt = 10; // значением выражения присваивания является 10
Сейчас вы можете подумать: все это, конечно, красиво и заумно, но какая от этого польза? Дело в том, что оператор присваивания возвращает значение и это же самое значение можно использовать для другого экземпляра инструкции присваивания:
int myInt;
int myInt2;
myInt2 = myInt = 10;
Значение, присвоенное переменной myInt2, является значением, которое было присвоено переменной myInt. Инструкция присваивания дает одно и то же значение обеим переменным. Этот прием пригодится, если нужно инициализировать сразу несколько переменных одним и тем же значением. Всем, кто читает ваш код, будет абсолютно понятно, что у всех переменных должно быть одно и то же значение:
myInt5 = myInt4 = myInt3 = myInt2 = myInt = 10;
Рассматривая данный вопрос, можно прийти к заключению, что оператор присваивания имеет ассоциативность справа налево. Первым происходит самое правое присваивание, и присвоенное значение распространяется по переменным справа налево. Если какая-нибудь из переменных ранее уже имела значение, оно переписывается присваиваемым значением.
Но к данной конструкции нужно относиться весьма осмотрительно. Одной из часто совершаемых ошибок является то, что новички в программировании на C# пытаются объединить такое применение оператора присваивания с объявлениями переменных. Например, можно предположить, что следующий код создаст и инициализирует три переменные одним и тем же значением (10):
int myInt, myInt2, myInt3 = 10;
Это вполне приемлемый код C# (поскольку он проходит компиляцию). Он объявляет переменные myInt, myInt2 и myInt3 и инициализирует переменную myInt3 значением 10. Но он не инициализирует myInt или myInt2. Если попытаться использовать myInt или myInt2 в подобном выражении:
myInt3 = myInt / myInt2;
компилятор выдаст ошибки, связанные с использованием локальных переменных, которым не присвоены значения:
Use of unassigned local variable 'myInt'
Use of unassigned local variable 'myInt2'
Если к значению переменной нужно прибавить 1, можно, как показано далее, воспользоваться оператором +:
count = count + 1;
Но добавление 1 к переменной (операция инкремента) встречается настолько часто, что в C# для этой цели предоставляется собственный оператор ++. Чтобы увеличить значение переменной count на 1, можно написать следующую инструкцию:
count++;
Аналогично этому в C# для операции декремента предоставляется оператор --, которым можно воспользоваться для вычитания 1 из значения переменной:
count--;
Операторы ++ и -- являются унарными, а это означает, что они получают только один операнд. Они имеют одинаковый приоритет и обладают левой ассоциативностью (вычисляются слева направо).
Операторы инкремента (++) и декремента (--) необычны тем, что их можно ставить либо перед, либо после переменной. Помещение символов оператора перед переменной называется префиксной формой оператора, а их помещение после переменной — постфиксной формой. Рассмотрим примеры:
count++; // постфиксный инкремент
++count; // префиксный инкремент
count--; // постфиксный декремент
--count; // префиксный декремент
Какая бы форма, префиксная или постфиксная, оператора ++ или -- ни использовалась, для переменной нет никакой разницы, она все равно подвергнется инкрементированию или декрементированию. Например, если вы напишете count++, значение count увеличится на единицу, и если вы напишете ++count, оно также увеличится на единицу. Зная об этом, вы, наверное, спросите: к чему эти два способа написания одной и той же операции? Чтобы понять смысл ответа, нужно вспомнить, что ++ и -- являются операторами и что все операторы используются для вычисления выражения, имеющего значение. Значение, возвращаемое count++, является значением count до добавления к нему единицы, а значение, возвращаемое ++count, является значением count после добавления к нему единицы. Рассмотрим пример:
int x;
x = 42;
Console.WriteLine(x++); // x теперь равен 43, а на консоль выводится 42
x = 42;
Console.WriteLine(++x); // x теперь равен 43, и на консоль выводится 43
Чтобы запомнить, что происходит с операндами, нужно посмотреть на порядок следования элементов (операнда и оператора) в префиксном или постфиксном выражении. В выражении x++ сначала стоит переменная, следовательно, ее значение используется в качестве значения выражения до увеличения х на единицу. В выражении ++x сначала стоит оператор, следовательно, его операция выполняется до того, как x вычисляется как результат.
Чаще всего эти операторы используются в инструкциях while и do, которые представлены в главе 5 «Использование инструкций составного присваивания и итераций». Если операторы инкремента и декремента используются изолированно, придерживайтесь постфиксной формы — и будьте в этом последовательны.
Ранее в этой главе было показано, что переменная объявляется путем указания типа данных и идентификатора:
int myInt;
Также упоминалось о том, что перед попыткой применения переменной ей нужно присвоить значение. Объявить и инициализировать переменную можно в одной и той же инструкции, как показано в следующей строке кода:
int myInt = 99;
Или же можно сделать это как в следующей строке кода, при условии, что myOtherInt является инициализированной целочисленной переменной:
int myInt = myOtherInt * 99;
Теперь вспомните, что значение, присваиваемое переменной, должно быть того же типа, что и переменная. Например, значение типа int может быть присвоено переменной с указанным типом данных int. Компилятор C# способен быстро определять тип выражения, используемого для инициализации переменной, и указывать на то, что оно не соответствует типу переменной. Как показано в следующих примерах, путем использования ключевого слова var на месте типа компилятор C# можно также попросить определить тип переменной из выражения и воспользоваться этим типом при объявлении переменной:
var myVariable = 99;
var myOtherVariable = "Hello";
Переменные myVariable и myOtherVariable называются неявно типизированными переменными. Ключевое слово var заставляет компилятор установить тип переменных из типов выражений, используемых для их инициализации. В этих примерах myVariable имеет тип int, а myOtherVariable относится к типу string. Но вам важно понять, что это пригодится только для объявления переменных и что после того, как переменная была объявлена, ей можно присваивать только значения предполагаемого типа. К примеру, далее в программе вы не сможете присваивать переменной myVariable значения типов float, double или string. Нужно также усвоить, что вы можете использовать ключевое слово var только тогда, когда для инициализации переменной указывается выражение. Следующее выражение считается недопустимым и вызывает ошибку компиляции:
var yetAnotherVariable; // Ошибка – компилятор не может установить тип
ВНИМАНИЕ Тем, кому в прошлом приходилось заниматься программированием на Visual Basic, должен быть знаком тип Variant, который можно использовать для хранения в переменной значения любого типа. Я акцентирую ваше внимание здесь и сейчас на том, что вы должны забыть все, что когда-либо изучали о переменных типа Variant при программировании на Visual Basic. Хотя ключевые слова var и Variant выглядят похожими, они означают совершенно разные вещи. При объявлении переменной в C# с использованием ключевого слова var тип значений, присваиваемых переменной, не может изменяться и должен быть таким же, как при ее инициализации.
Если вы педант, то, наверное, уже поскрипываете зубами, недоумевая, почему разработчики такого чистого языка, каким является C#, позволили вкрасться в него такой особенности, как использование ключевого слова var. Ведь это похоже на оправдание чрезмерной лени у определенной части программистов и может усложнить понимание того, что делает программа, или отслеживание допущенной ошибки (и даже с легкостью может способствовать появлению новых ошибок в коде вашей программы). Но поверьте мне, что var находится в C# на своем законном месте, в чем вы сможете убедиться, изучая следующие главы. И тем не менее на данный момент мы будем придерживаться использования явно типизированных переменных, прибегая к неявной типизации в случае крайней необходимости.
В данной главе вы увидели, как создавать и использовать переменные, и узнали о некоторых наиболее распространенных типах данных, доступных для переменных в C#. Вы также узнали об идентификаторах. Кроме того, вы воспользовались несколькими операторами для создания выражений и узнали о том, как в зависимости от уровней приоритета и ассоциативности операторов определяется способ вычисления выражений.
Если хотите продолжить работу и изучить следующую главу, оставьте открытой среду Visual Studio 2015 и переходите к главе 3.
Если хотите выйти из среды Visual Studio 2015, то в меню Файл щелкните на пункте Выход (Exit). Если увидите диалоговое окно с предложением сохранить изменения, щелкните на кнопке Да (Yes) и сохраните проект.
Чтобы | Сделайте следующее |
Объявить переменную | Напишите название типа данных, затем имя переменной, после чего поставьте точку с запятой, например: int outcome; |
Объявить переменную и присвоить ей начальное значение | Напишите название типа данных, затем имя переменной, после чего поставьте оператор присваивания и начальное значение. Завершите инструкцию точкой с запятой, например: int outcome = 99; |
Изменить значение переменной | Напишите имя переменной слева, за ним поставьте оператор присваивания, далее выражение, вычисляющее новое значение, и завершите инструкцию точкой с запятой, например: outcome = 42; |
Создать строку, представляющую значение, хранящееся в переменной | Вызовите в отношении переменной метод ToString, например: int intVar = 42; string stringVar = intVar.ToString(); |
Преобразовать строку в целое число | Вызовите метод System.Int32.Parse, например: string stringVar = "42"; int intVar = System.Int32.Parse(stringVar); |
Изменить очередность применения операторов | Воспользуйтесь круглыми скобками для принудительного задания порядка вычисления, например: (3 + 4) * 5 |
Присвоить одно и то же значение нескольким переменным | Воспользуйтесь инструкцией присваивания, перечисляющей все переменные, например: myInt4 = myInt3 = myInt2 = myInt = 10; |
Увеличить или уменьшить значение переменной на единицу | Воспользуйтесь оператором ++ или --, например: count++; |