Г. Шилдт - С#4.0 Полное руководство (1160795), страница 74
Текст из файла (страница 74)
Структуры относятся к типам значений, и поэтому ими можно оперировать непосредственно, а не по ссылке. Следовательно, для работы со структурой вообще не требуется переменная ссылочного типа, а это означает в ряде случаев существенную экономию оперативной памяти. Более того, работа со структурой не приводит к ухудшению производительности, столь характерному для обращения к объекту класса. Ведь доступ к структуре осуществляется непосредственно, а к объектам — по ссылке, поскольку классы относятся к данным ссылочного типа. Косвенный характер доступа к объектам подразумевает дополнительные издержки вычислительных ресурсов на каждый такой доступ, тогда как обращение к структурам не влечет за собой подобные издержки.
И вообще, если нужно просто сохранить группу связанных вместе данных, не требующих наследования и обращения по ссылке, то с точки зрения производительности для них лучше выбрать структуру. Ниже приведен еще один пример, демонстрирующий применение структуры на практике. В этом примере из области электронной коммерции имитируется запись транзакции. Каждая такая транзакция включает в себя заголовок пакета, содержащий номер и длину пакета.
После заголовка следует номер счета и сумма транзакции. Заголовок пакета представляет собой самостоятельную единицу информации, и поэтому он организуется в отдельную структуру, которая затем используется для создания записи транзакции или же информационного пакета любого другого типа. // Структуры удобны для группирования небольших обьемов данных. цяьпд Зуягеш1 О Определить структуру пакета. ятсцсг Раскеснеас(ег ( рпЫхс ц1пс Раскицш( // номер пакета рцЫ1с цяьотс Расхьеп1 // длина пакета ) // Использовать структуру Раскегнеабег для создания записи транзакции // в сфере электронной коммерции.
с1аяя Тгапяасгьоп ( ягасьс цьпс тоапяасицш = 0; 396 Часть ). Язык С№ Раскеснеаг)ег рйг // ввести Структуру РаскегНеаиег в класс Тгапяассьоп ясггп9 ассоипгниюг СоиЬ1е аюоипгг риьььс Тгапвасс1оп(ясггп9 асс, Соивье ча1) // создать заголовок пакета рь.Расхмию = ггапяасмию++1 РЬ.Раскъеп = 512; // произвольная длина ассоипснии = асс; азоипг = ча1; ) Сымитировать транзакцию. риЬТТс чогв яепСТгапяассьоп() Сопяо1е.нг1сеььпе("Пакет 4: Длина: ",хп Счет Сумма: " + РЬ.Раскнию + + РЬ.Раскъеп 4: " ь аосоипснию (О."С] )п", аюоипг); Продемонстрировать применение структуры в виде пакета транзакции. с1аяв РаскеГОезо ( ягаггс чо18 Ма1п() ( тгапяасгьоп с = пен тгапяасг1оп("31243", -100.12); Тгапяасг1оп Г2 = пен Тгапяасс1оп(тй84855", 345.25); Тгапяассьоп ГЗ = пен Тгапяасг1оп("8475-09", 9800.00); С.зепСТгапяассьоп(]; Г2.яепНТгапяассьоп(); СЗ.яепсТгапяасгьоп(); ) ) Вот к какому результату может привести выполнение этого кода.
Пакет 4: О, Длина: 512, Счет $: 31243, Сумма: (8100.12) Пакет Ф: 1, Длина: 512, Счет 4: й84855, ~умма: 8345.25 Пакет $: 2, Длина: 512, Счет 4: 8475-09, Сумма: 89,800.00 Структура Рас)гегнеас)ег оказывается вполне пригодной для формирования заголовка пакета транзакции, поскольку в ней хранится очень небольшое количество данных, не используется наследование и даже не содержатся методы. Кроме того, работа со структурой РасхеСНеаг)е г не влечет за собой никаких дополнительных издержек, связанных со ссылками на объекты, что весьма характерно для класса.
Следовательно, структуру РаскеСНеаг(е г можно использовать для записи любой транзакции, не снижая эффективность данного процесса. Глава 12. Интерфейсы, струнтуры и перечисления 397 Любопытно, что в Стт также имеются структуры и используется ключевое слово зсгпог. Но эти структуры отличаются от тех, что имеются в С((. Так, в Ст+ структура относится к типу класса, а значит, структура и класс в этом языке практически равноценны и отличаются друг от друга лишь доступом по умолчанию к их членам, которые оказываются закрытыми для класса и открытыми для структуры.
А в С(( структура относится к типу значения, тогда как класс — к ссылочному типу. Перечисления Перечисление представляет собой множество именованных целочисленных констант. Перечислимый тип данных объявляется с помощью ключевого слова епппь Ниже приведена общая форма обьявления перечисления: епои имя (список перечисления); где имя — это имя типа перечисления, а список перечисления — список идентификаторов, разделяемый запятыми. В приведенном ниже примере объявляется перечисление Арр1е различных сортов яблок. епои Арр1е ( Зопагьап, Оо1г(еппе1, Кег(ое1, Хгпззар, Согг1апг(, Нс1ппозь Следует особо подчеркнуть, что каждая символически обозначаемая константа в перечислении имеет целое значение.
Тем не менее неявные преобразования перечислимого типа во встроенные целочисленные типы и обратно в С(( не определены, а значит, в подобных случаях требуется явное приведение типов. Кроме того, приведение типов требуется при преобразовании двух перечислимых типов. Но поскольку перечисления обозначают целые значения, то их можно, например, использовать для управления оператором выбора зиагоп или же оператором цикла Гог. Для каждой последующей символически обозначаемой константы в перечислении задается целое значение, которое на единицу больше, чем у предыдущей константы.
По умолчанию значение первой символически обозначаемой константы в перечислении равно нулю. Следовательно, в приведенном выше примере перечисления Арр1е константа допагйап равна нулю, константа йо1с(епОе1 — 1, константа пег(пе1 — 2 и т.д. Доступ к членам перечисления осуществляется гю имени их типа, после которого следует оператор-точка.
Например, при выполнении фрагмента кода Сопзо1е.нггоеьвпе(лрр1е.кеоое1 т " имеет значение (тпг)лрр1е.нзг(ое1); выводится следующий резуль.тат. нег(эе1 имеет значение 2 Как показывает результат выполнения приведенного выше фрагмента кода, для вывода перечислимого значения используется его имя. Но для получения этого значения требуется предварительно привести его к типу 1п О. Ниже приведен пример программы, демонстрирующий применение перечисления Арр1е. 398 Часть!. Язык СФ // Продемонстрировать применение перечисления. ця1пд Зуясещ) с1аяя Епцщвеюо ( епцщ Арр1е ( Зопаглап, По1беппе1, Вес(ое1, ХьпеяаР, Согг1апб, Мс1псояЛ ) ) ясасзс чотг) Ма1п () ( ясг1пс(] со1ог = ( "красный", "желтый", "красный", "красный", "красный", "красновато-зеленый" )) Арр1е ьт // объявить переменную перечислимого типа // Использовать переменную 1 для циклического // обращения к членам перечисления.
гог(1 = Арр1е.юопаслапт 1 <= Арр1е.мс1пгояги 1++) Сопяо1е.нггсе11пе(1 Ь " имеет значение " + (1пг)1) Сопяо1е.нгьгеЬ1пе () // Испольэовать перечисление для индексирования массива. гог(1 = Арр1е.допаслапт 1 <= Арр1е.мс1пгоя)и 1++) Сопзо1е.кгьгеььпе("Цвет сорта со1ог ( (1пг) 1) ); ) Ниже приведен результат выполнения этой программы. Зопагьап имеет значение 0 По1беппе1 имеет значение 1 Вебое1 имеет значение 2 изпяар имев~ значение 3 Согг1апб имеет значение 4 Мс1ппоял имеет значение 5 Обратите внимание на то, как переменная типа Арр1е управляет циклами гог. Значения символически обозначаемых констант в перечислении Арр1е начинаются с нуля, поэтому их можно использовать для индексирования массива, чтобы получить цвет каждого сорта яблок.
Обратите также внимание на необходимость производить приведение типов, когда перечислимое значение используется для индексирования Цвет Цвет Цвет Цвет Цвет Цвет сорта сорта сорта сорта сорта сорта ЗопаСЛап — красный По1бепве1 — желтый Вебое1 — красный Х1пяар — красный Согс1апб — красный Мс1пгояЛ вЂ” красновато-зеленый Глава'12.
ИнтерФейсы, структуры и перечисления 399 массива. Как упоминалось выше, в С(( не предусмотрены неявные преобразования перечислимых типов в целочисленные и обратно, поэтому для этой цели требуется явное приведение типов. И еще одно замечание; все перечисления неявно наследуют от класса я у а Севг. еповь который наследует от класса Бузгекг. Ча1оеТуре, а тот, в своЮ очЕредь, — от класса оЬЗесг. Инициализация перечисления Значение одной или нескольких символически обозначаемых констант в перечислении можно задать с помощью инициализатора.
Для этого достаточно указать после символического обозначения отдельной константы знак равенства и целое значение. Каждой последующей константе присваивается значение, которое на единицу больше значения предыдущей инициализированной константы. Например, в приведенном ниже фрагменте кода константе пег)пе1 присваивается значение 10. соим Ьрр1е ( Зооагиао, Оо1г)еппе1, нег)эе1 = 10, Игоезар, Согг1апг), Мстпгоай ); В итоге все константы в перечислении принимают приведенные ниже значения. 0 .)оправ оо)г)епое) пег(ое) 10 )Мпевар Сог6апг) 12 мс)п(оап Указание базового типа перечисления По умолчанию в качестве базового для перечислений выбирается тип 1пс, тем не менее перечисление может быть создано любого целочисленного типа, за исключением сЬаг.
Для того чтобы указать другой тип, кроме ьпг, достаточно поместить этот тип после имени перечисления, отделив его двоеточием. В качестве примера ниже задается тип Ьуге для перечисления Арр1е. епощ Арр1е : ЬуСе ( Зопаг)гас, Со1г)епое1, Нег)ое1, игпеаар, Согс1аог), Мс1оооаь )г Теперь константа лрр1е . х1пе вар, например, имеет количественное значение типа Ьусе.
Применение перечислений На первый взгляд перечисления могут показаться любопытным, но не очень нужным элементом С(), но на самом деле это не так. Перечисления очень полезны, когда в программе требуется одна или несколько специальных символически обозначаемых констант. Допустим, что требуется написать программу для управления лентой конвейера на фабрике.