3.1.3.Выполнение явных преобразований с помощью команд преобразования
Способ явного преобразования, использовавшийся во многих предыдущих примерах, несколько отличается от рассмотренного в данной лекции. Прежде осуществляли преобразования строковых значений в числа посредством таких команд, как Convert.ToDouble(), которые совершенно очевидно не смогут работать с любой строкой. Если, например, попытаться преобразовать строку "Number" в число типа double с помощью Convert. ToDouble (), то в процессе выполнения кода будет открыто диалоговое окно с сообщением:
"Необрабатываемая исключительная ситуация типа 'System.FormatException' в mscorlib.dll. Дополнительная информация: Входная строка имеет неверный формат.".Операция не выполнена. Для того чтобы подобный тип преобразования мог осуществиться, передаваемая строка должна быть допустимым представлением числа и это число не должно приводить к переполнению. Допустимым называется такое представление числа, которое содержит необязательный знак (плюс или минус), ноль или несколько цифр, необязательную десятичную точку, за которой следует одна или несколько цифр, а также необязательный символ
"е" или "Е", за которым следуют необязательный знак и одна или несколько цифр, и ничего более, кроме пробелов (располагающихся перед или после этой последовательности).
Используя все эти дополнительные опции, можно распознавать строки типа -1.245е-24 как число.
Существует много явных преобразований, которые могут быть определены таким же образом (табл. 3.2).
Здесь val может быть переменной почти любого типа (а если она не может быть обработана данными командами, то компилятор выдаст соответствующее сообщение).
К сожалению, как можно заметить из приведенной таблицы, имена команд преобразования несколько отличаются от названий типов, принятых в С#; например, для того чтобы произвести преобразование в тип int, следует использовать
Команда | Результат |
Convert.ToBoolean(val) | val преобразовано в bool |
Convert.ToByte(val) | val преобразовано в byte |
Convert.ToChar(val) | val преобразовано в char |
Convert.ToDecimal(val) | val преобразовано в decimal |
Convert. ToDouble I. val) | val преобразовано в double |
Convert.Tolntl6(val) | val преобразовано в short |
Convert.Tolnt32(val) | val преобразовано в int |
Convert.Tolnt64(val) | val преобразовано в long |
Convert. ToSBy te (val) | val преобразовано в sbyte |
Convert.ToSingle(val) | val преобразовано в float |
Convert.ToStnng(val) | val преобразовано в string |
Convert.ToUInt16(val) | val преобразовано в ushort |
Convert.ToUInt32(val) | val преобразовано в uint |
Convert.ToUInt64(val) | val преобразовано в ulong |
Команду Convert.ToInt32(). Это объясняется тем, что имена в командах взяты из пространства имен System .NET Таблица 3.2 – Команды явных преобразований Framework и не являются родными для С#. Зато благодаря этому их можно использовать из любых других языков, совместимых с NET.
Необходимо отметить один важный момент: в процессе таких преобразовании всегда осуществляется контроль за переполнением, при этом ключевые слова checked и unchecked, а также установки, заданные для всего проекта, влияния не имеют.
3.2.Сложные типы переменных
Итак, к настоящему моменту были рассмотрены все простые типы переменных, которые используются в С#. Кроме них, в С# существует три более сложных (но очень полезных) типа переменных:
- перечислимый тип; - структуры; - массивы.
3.2.1.Перечислимый тип
Все типы, которые рассматривались до сих пор (за исключением типа string), имеют четко определенное множество допустимых значений. Это множество может быть настолько большим (как, например, у типа double), что его можно рассматривать в качестве континуума, однако все равно это фиксированное множество. В качестве простейшего примера можно привести тип bool, который может принимать только одно из двух значений: true или false.
Существует большое количество ситуаций, когда требуется переменная, принимающая значение из фиксированного множества. Например, может возникнуть необходимость в использовании переменной типа orientation (ориентирование), которая принимает одно из значений: north (север), south (юг), east (восток) или west (запад).
В подобных ситуациях очень полезным может оказаться перечислимый тип. Он позволяет сделать как раз то, что требуется для переменной orientation: определить тип, который принимает одно значение из конечного множества задаваемых нами значений.
Все, что для этого требуется сделать,– это создать свой собственный перечислимый тип, который будет называться orientation и для которого будут существовать четыре возможных значения, перечисленных выше. Обратите внимание, что это является дополнительным шагом: не просто объявляется переменная некоторого типа, сначала объявляется и подробно описывается создаваемый пользователем тип и только после этого имеется возможность объявить переменную данного типа.
3.2.2.Определение перечислимых типов
Перечислимый тип описывается с помощью ключевого слова enum следующим образом enum имяТипа { значение1, значение2, значение3, значениеN }Затем объявляются переменные этого типа <имяТипа имяПеременной>. Им присваиваются конкретные значения <имяПеременной> = <имяТипа.значение>;.
Перечислимый тип обладает базовым типом (underlying type), который используется для хранения. Любое из значений, которые этот тип может принимать, будет храниться в памяти как значение базового типа (по умолчанию это тип int) Однако существует возможность задать в качестве базового другой тип, добавив к описанию типа имя его базового типа
enum имяТипа : базовыйТип { | |
значение1, значение2, значение3, |
значениеN }
Перечислимые типы могут использовать в качестве базовых следующие типы byte, sbyte, short, ushort, int, uint, long и ulong.
По умолчанию каждому значению перечислимого типа автоматически присваивается соответствующее значение базового типа, начиная с нуля, в том порядке, в котором они описаны. Другими словами, значение 1 получит базовое значение 0, значение 2 – 1, значение 3 – 2 и т. д. Для того чтобы переопределить такой порядок, следует использовать оператор = и фактические базовые значения для каждого перечислимого значения.
enum имяТипа : базовыйТип { значение1 = фактическоеЗначение1, значение2 = фактическоеЗначение2, значение3 = фактическоеЗначение3, значениеN = фактическоеЗначениеN}
Кроме того, существует возможность задавать идентичные базовые значения для нескольких перечислимых значений, используя одно значение как базовое значение другого enum имяТипа : базовыйТип { значение1 = фактическоеЗначение1, значение2 = значение1, значение3,...
значениеN= фактическоеЗначениеN }
Всем значениям, оставшимся неуказанными, будут автоматически присвоены базовые значения, для этого используется последовательность, начинающаяся со значения, на единицу большего последнего явно заданного значения. В вышеприведенном объявлении значение3 получит базовое значение, равное значение1 + 1.
Обратите внимание, что это может привести к возникновению непредвиденных проблем, когда какие-либо из базовых значений, заданных после определения вроде значение2 = значение1, окажутся идентичными другим базовым значениям. Так, например, в следующей программе базовое значение для значение4 и для значение2 будет одним и тем же
enum имяТипа : базовыйТип { значение1 = фактическоеЗначение1, значение2, значение3 = значение1, значенне4,...
значениеN = фактическоеЗначениеN }
Это совершенно нормально, если, конечно, требуется добиться именно такого эффекта.
Обратите также внимание, что присваивание значений циклическим образом приведет к возникновению ошибки: enum имяТипа.базовыйТип { значение1 = значение2, значение2 = значение1 }
3.2.3.Структуры
Еще одним типом переменной, который требуется рассмотреть, является struct (сокращение от слова structure – "структура"). Структуры вполне соответствуют своему названию: это структуры данных, которые составлены из информации различного характера, возможно, из данных различных типов. Они позволяют программистам описывать свои собственные типы переменных, для которых данная структура является базовой. В качестве примера предположим, что необходимо хранить информацию о маршруте из одной точки в другую, включающую направление и расстояние в милях. Для простоты в качестве направления будет использоваться только одна из четырех сторон света (так что для описания направления вполне подойдет перечислимый тип orientation), а длина маршрута будет представлена типом double.