- •Тема 6. Основы программирования на языке c#
- •Условная операция
- •Операции checked и unchecked
- •Операция поглощения null
- •Безопасность типов
- •Преобразования типов
- •Неявные преобразования
- •Явные преобразования
- •Упаковка и распаковка
- •Проверка равенства объектов
- •Виртуальный метод Equals()
- •Статический метод Equals()
- •Проверка типов значений на равенство
- •Перегрузка операций
- •Как работают операции
- •Пример перегрузки операции: структура Vector
- •Добавление дополнительных перегрузок
- •Перегрузка операций сравнения
- •Пользовательские приведения
- •Реализация пользовательских приведений
- •Приведение между классами
- •Приведение между базовым и производным классами
- •Упаковывающие и распаковывающие приведения
- •Множественные приведения
Условная операция
Условная операция (? :), также известная, как тернарная операция это сокращенная форма конструкции if...else. Название отражает тот факт, что она работает с тремя операндами. Эта операция вычисляет выражение и возвращает одно из значений, если выражение истинно, и другое если выражение ложно.
Синтаксис выглядит следующим образом:
условие ? true_значение : false_значение
Здесь условие булевское выражение, которое должно быть вычислено, true_знaче- ние значение, которое возвращается, если условие истинно, а fаlsе_значение значение, которое возвращается, если условие ложно.
При аккуратном использовании условная операция может придать удивительную краткость разрабатываемым программам. Особенно удобно это бывает для передачи одного из нескольких аргументов при вызове функции. Вы можете использовать его для быстрого преобразования булевского выражения в строковое значение true или false. Также он удобен для отображения единственной или множественной формы существительного, например:
int х = l;
string s = х + " ";
s += (x == 1 ? "man" : "men");
Console.WriteLine(s) ;
Этот код отображает 1 man, если x равно 1, но отобразит корректную множественную форму английского языка для любого другого числа. Однако обратите внимание, что если вывод программы должен быть локализован для разных языков, то придется написать более сложные процедуры, принимающие во внимание грамматические правила этих языков.
Операции checked и unchecked
Рассмотрим следующий код:
byte b = 255;
b++;
Console.WriteLine(b.ToString());
Тип данных byte может содержать только значения от 0 до 255, поэтому инкремент значения b вызовет переполнение. Как CLR обработает это — зависит от множества факторов, включая опции компилятора, поэтому, когда возникает опасность переполнения, необходимо каким-то образом удостовериться в получении правильного результата.
Для этого C# предлагает операции checked и unchecked. Если пометить блок кода как checked, CLR осуществит контроль переполнения, и в случае обнаружения такового сгенерирует исключение Overf lowException. Изменим код примера, включив в него операцию checked:
byte b = 255;
checked
{
b++;
}
Console.WriteLine(b.ToString());
Если попытаться запустить этот код, будет получено следующее сообщение об ошибке:
Unhandled Exception: System.OverflowException: Arithmetic operation
resulted in an overflow at Wrox.ProCSharp.Basics.OverflowTest.
Main(String[] args)
Необработанное исключение: System. OverflowException: Арифметическая
операция дала в результате переполнение в Wrox.ProCSharp.Basics.
OverflowTest.Main(String[] args)
Указание опции компилятора /checked позволяет включить принудительный контроль переполнения для всего непомеченного кода программы.
Если необходимо подавить проверку переполнения, код следует пометить как unchecked:
byte b = 255;
unchecked
{
b++;
}
Console.WriteLine(b.ToString());
В данном случае никаких исключений не будет сгенерировано, однако произойдет потеря данных поскольку тип byte не может хранить значение 256, переполняющие биты будут отброшены, и переменная b получит значение 0.
Следует отметить, что поведение unchecked выбирается по умолчанию. Единственный случай, когда может понадобиться явно указать ключевое слово unchecked это в случае возникновения потребности в нескольких строках unchecked-кода внутри большого блока, явно помеченного как checked.
Операция is
Операция is позволяет проверить, совместим ли объект с определенным типом. В данном случае “совместимость” означает, что объект либо имеет этот тип, либо наследуется от этого типа. Например, для проверки, совместима ли переменная с типом object, используется приведенный ниже код:
int i = 10;
if (i is object)
{
Console.WriteLine(”i является object");
}
Как и все типы С#, int унаследован от object, поэтому выражение i is object вычисляется в данном случае как true, и сообщение будет отображено.
Операция as
Операция as применяется для выполнения явного преобразования типа ссылочных переменных. Если преобразуемый тип совместим с указанным, преобразование проходит успешно. Однако если типы несовместимы, то операция as возвращает значение null. Как показано в следующем коде, попытка преобразовать ссылку object в string возвращает null, если только ссылка object на самом деле не ссылается на экземпляр string:
object o1 = "Некоторая строка";
object о2 = 5;
string s1 = o1 as string; // s1 = "Некоторая строка"
string s2 = o2 as string; // s2 = null
Операция as позволяет выполнить безопасное преобразование типа за один шаг, без необходимости первоначальной проверки его на совместимость с помощью операции is до собственно преобразования.
Операция sizeof
Чтобы определить место (в байтах), требуемое для размещения в стеке типа значения, необходимо воспользоваться операцией sizeof:
Console.WriteLine(sizeof(int));
Этот код отобразит число 4, потому что int занимает в памяти 4 байта.
Если операция sizeof применяется со сложными (а не с примитивными) типами, код понадобится заключить в блок unsafe, как показано ниже:
unsafe
{
Console.WriteLine(sizeof(int));
}
Небезопасный код подробно рассматривается в разделе 6.13.
Операция typeof
Операция typeof возвращает объект System.Туре, представляющий указанный тип. Например, typeof (string) вернет объект Туре, представляющий тип System.String. Это удобно, если необходимо использовать рефлексию, чтобы динамически получить информацию об объекте. Рефлексия рассматривается в разделе 6.14.
Типы и операции, принимающие значение null
Взглянем на булевский тип. Он допускает присваивание значения либо true, либо false. Но как в таком случае поступить, если нужно определить неизвестное значение? Здесь как раз пригодится тип, допускающий значение null (nullable type). Если в своих программах вы используете типы, допускающие значение null, то всегда должны учитывать эффект, который дает применение значения null с различными операциями. Обычно при использовании унарной или бинарной операции с такими типами результатом будет null, если один или оба операнда будут равны null. Например:
int? а = null;
int? b = а + 4; // Ь = null
int? с = а * 5; // с = null
Однако при сравнении типов, принимающих значение null, если хотя бы один из операндов будет null, сравнение всегда даст false. Это значит, что нельзя ожидать, что условие даст в результате true, только потому, что противоположное условие дает false, как часто случается в программах, работающих с типами, не принимающими null. Например:
int? а = null;
int? b = -5;
if (a >= b)
System.Console.WriteLine("a >= b");
else
System.Console.WriteLine("a < b");
Возможность значения null означает, что произвольно комбинировать в выражении типы, принимающие значения null, и типы, не допускающие их, нельзя. Это обсуждается ниже в подразделе “Преобразования типов ”.
