Сложные типы переменных Итак, к настоящему моменту мы рассмотрели все простые типы переменных, которые используются в С#. Кроме них, в С# существует три более сложных (но очень полезных) типа переменных: • Перечислимый тип • Структуры • Массивы Перечислимый тип Все типы, которые рассматривались до сих пор (за исключением типа string), имеют четко определенное множество допустимых значений. Это множество может быть настолько большим (как, например, у типа double), что его можно рассмат- ривать в качестве континуума, однако все равно это фиксированное множество. В качестве простейшего примера можно привести тип bool, который может прини- мать только одно из двух значений: true или false. Существует большое количество ситуаций, когда требуется переменная, при- нимающая значение из фиксированного множества. Например, может возникнуть необходимость в использовании переменной типа orientation (ориентирование), которая принимает одно из значений: north (север), south (юг), east (восток) или west (запад). В подобных ситуациях очень полезным может оказаться перечислимый тип. Он позволяет сделать как раз то, что требуется для переменной orientation: опреде- лить тип, который принимает одно значение из конечного множества задаваемых нами значений. Все, что для этого требуется сделать,— это создать свой собственный перечис- лимый тип, который будет называться orientation и для которого будут существо- вать четыре возможных значения, перечисленных выше. Обратите внимание, что это является дополнительным шагом: мы не просто объявляем переменную неко- торого типа, мы сначала объявляем и подробно описываем создаваемый пользова- телем тип и только после этого получаем возможность объявить переменную данного типа. 86 Глава 5 Определение перечислимых типов Перечислимый тип описывается с помощью ключевого слова enum следующим образом: 1 '^; ": :-::::::-:;:;:Щ#Й1Щ значение!, Затем объявляются переменные этого типа: имяТипа имяПеременной; Им присваиваются конкретные значения: имяПеременной = имяТипа. значение; Перечислимый тип обладает базовым типом (underlying type), который исполь- зуется для хранения. Любое из значений, которые этот тип может принимать, будет храниться в памяти как значение базового типа (по умолчанию это тип int). Одна- ко существует возможность задать в качестве базового другой тип, добавив к опи- санию типа имя его базового типа: епшп имяТипа : базовыйТип { значение1, значение2, значениеЗ, значение^ У Перечислимые типы могут использовать в качестве базовых следующие типы: byte, sbyte, short, ushort, int, uint, long И ulong. По умолчанию каждому значению перечислимого типа автоматически присваи- вается соответствующее значение базового типа, начиная с нуля, в том порядке, в котором они описаны. Другими словами, значение! получит базовое значение О, значение2 — 1, значениеЗ — 2 И Т. Д. Для ТОГО чтобы переопределить такой ПОря- док, следует использовать оператор = и фактические базовые значения для каждо- го перечислимого значения: enum имяТипа : базовыйТип { . ^ -—«яда значение2 - фактическоеЗначение2, значениеЗ = фактическоеЗначениеЗ, значениеЫ = фактическоеЗначениеЫ > Кроме того, существует возможность задавать идентичные базовые значения для нескольких перечислимых значений, используя одно значение как базовое зна- чение другого: enum имяТипа : базовыйТип { значение! = фактическоеЗначение!, значение! = значение!, Дополнительные сведения п „„ 87 значениеЗ, . значением = ФактическоеЗначениеЫ одним и тем же: enum имяТипа : базовыйТил значение! = фактическоеЗначение! значение2, значениеЗ = значение!, для для значениеы е совершенно „ор„м ь в о , есл11, „„„„„„, enum имяТипа : базовыйТип значение! = значение2/ значение2 - значение! Теперь давайте посмотрим, каким образом все это можно использовать. 1. Создайте новое консольное приложение с именем СпО5ЕхО2 В Директории C:\BegCSharp\Chapter5. 2- Добавьте следующий код в ciassi.cs: namespace ChO5ExO2 enum orientation : byte ЩШШШШШШШШ^ШШт north = l , east = 3 , } ' : . i . . . : I I . | .':•, /// <summary> /// Summary description for Classl. /// </summary> class Classl static void Main (string [] args) 88 Глава 5 orientation myDirection - orientation.north; Console.WriteLine(*myDirection = {0}", myDirection) 3. Запустите приложение. На консоли появится следующий выходной поток: 4. Выйдите из приложения и измените программу следующим образом: byte directionByte; string directionString; orientation myDirection = orientation.norths- Console. WriteLine("myDirection = {0}", myDirection); directionByte = {byte)myDirection; ofirectionString = Convert .ToString (myDirection) ; Console.WriteLine("byte equivalent - {0}", directionByte); : : Console.WriteLine("string equivalent = : {0}", directionString); 5. Повторно запустите приложение: El!O\8e§CSharp\Ch string, equivalent' ~ north Pi*ess any key to continue Как это работает В данной программе определяется и используется перечислимый тип с именем orientation. Первое, на что следует обратить внимание: код с описанием типа по- мещен в пространство имен chO5ExO2, а не в то место, где находится остальной код. Это сделано потому, что в процессе выполнения программы не происходит по- следовательного выполнения строк определения, как это имеет место с другими строками кода приложения. Выполнение приложения начинается с определяемого нами места, причем приложение имеет доступ к новому типу, поскольку принадле- жит тому же пространству имен. Первый вариант нашего примера демонстрирует основной метод создания пере- менной нового типа, присваивание ей значения и вывод этого значения на экран. Затем мы модифицировали код, чтобы показать преобразование перечислимых значений в другие типы. Заметьте, что в таких случаях необходимо использовать Дополнительные сведения о переменных #9 явное преобразование. Несмотря на то что базовым типом типа orientation явля- ется тип byte, нам все равно приходится использовать явное приведение типа (byte) ДЛЯ Преобразования Значения переменной myDirection В ТИП byte: directionByte = (byte)myDirection; Такое же явное приведение типа требуется и для обратного преобразования, когда тип byte нужно преобразовать в тип orientation. Например, для преобразо- вания переменной типа byte с именем myByte в тип orientation и присвоения получившегося значения переменной myDirection можно воспользоваться следую- щим кодом: myDirection = (orientation)myByte; Естественно, в данном случае необходимо действовать очень аккуратно, посколь- ку не каждое из допустимых значений переменной типа byte соответствует какому- либо из описанных значений переменной типа orientation. В переменных типа orientation вполне могут храниться и другие значения типа byte, и, хотя это не приведет к непосредственному возникновению ошибки, логика дальнейшего вы- полнения приложения может быть нарушена. Для получения строкового значения из значения перечислимого типа можно ис- пользовать Convert.ToString(): directionString = Convert.ToString(myDirection); Приведение (string) в данном случае не будет выполняться, поскольку здесь требуется более сложная обработка, нежели простой перенос данных, хранящихся в переменной перечислимого типа, в переменную типа string. В качестве альтернативы можно воспользоваться командой ToString о самой переменной. Следующий код даст точно такой же результат, что и использование Convert.ToString()! directionString = myDirection.ToString(); Обратное преобразование значения типа string в значение перечислимого типа также возможно, однако для этого потребуется немного более сложный синтаксис. Для преобразований такого рода существует специальная команда Enum.ParseO, которая используется следующим образом: (перечислимыйТип)Епит> Parse {typeof (перечислимыйТип) , значениеСтрокиПеречислимогоТила); Здесь задействован еще один оператор — typeof, который позволяет получать тип своего операнда. М ы могли бы воспользоваться им для нашего перечислимого типа orientation следующим образом: .-..•.,••••..•.• string myString = -north*"; : orientation myDirection = (orientation) Enum. Parse (typeof (orientation, myString) ; Естественно, далеко не каждое строковое значение будет соответствовать какому- либо значению типа orientation. Использование значения, которому не соответст- вует ни одно из значений перечислимого типа, приведет к возникновению ошибки. Как и все в С#, эти значения чувствительны к регистру, поэтому мы получим ошибку даже в том случае, если наша строка будет соответствовать перечислимо- му значению во всем, кроме регистра (например, если переменной myString будет присвоено значение "North" вместо "north").
|