Г. Шилдт - Полный справочник по C# (1160789), страница 63
Текст из файла (страница 63)
Структуры этим не страдают. В общем случае,если вам нужно хранить небольшую группу связанных данных, но не нужно обеспечивать наследование и использовать другие достоинства ссылочных типов, типs t r u c t может оказаться более предпочтительным вариантом.Рассмотрим еще один пример, демонстрирующий, как использовать структуру напрактике.
Эта программа имитирует запись транзакции. Одна запись содержит заголовок пакета с его номером и длиной. За этими данными указывается номер счета иобъем транзакции. Поскольку заголовок пакета представляет собой самодостаточнуюединицу информации, он организован в виде структуры. Эту структуру затем можноиспользовать для создания записи транзакции или любого другого типа информационного пакета.// Структуры прекрасно работают при группировании данных.using System;// Определяем структуру пакета,struct PacketHeader {public uint packNum;// Номер пакета.public ushort packLen; // Длина пакета.}Глава 12. Интерфейсы, структуры и перечисления343// Используем структуру PacketHeader для создания// электронной записи транзакции,class Transaction {static uint transacNum = 0;PacketHeader ph;// Включаем в транзакцию// структуру PacketHeader.string accountNum;double amount;public Transaction(string ace, double val) {// Создаем заголовок пакета.ph.packNum = transacNum++;ph.packLen = 512; // arbitrary lengthaccountNum = ace;amount = val;// Имитируем транзакцию.public void sendTransaction() {Console.WriteLine("Пакет #: " + ph.packNum +", Длина: " + ph.packLen +",\nСчет #: " + accountNum +", Сумма: {0:C}\n", amount);,•// Демонстрируем использование пакетной обработки,class PacketDemo {public static void Main() {Transaction t = new Transaction("31243", -100.12);Transaction t2 = new Transaction("AB4655", 345.25);Transaction t3 = new Transaction("8475-09", 9800.00)t.sendTransaction();t2.sendTransaction() ;t3.sendTransaction() ;При выполнении этой программы были получены следующие результаты.Пакет #: 0, Длина: 512,Счет #: 31243, Сумма: ($100.12)Пакет #: 1, Длина: 512,Счет #: АВ4655, Сумма: $345.25Пакет #: 2, Длина: 512,Счет #: 8475-09, Сумма: $9,800.00Выбор для данных PacketHeader типа структуры вполне оправдан, поскольку этиданные имеют небольшой объем, не наследуются и даже не содержат методов.
В качестве структуры объект типа PacketHeader не требует дополнительных затрат системных ресурсов на доступ через ссылку, как в случае класса. Таким образом, структуруPacketHeader можно использовать для записей транзакций любого типа без ущербадля эффективности.344Часть I. Язык С#Интересно отметить, что в языке C++ также можно определять структуры с помощью ключевого слова s t r u c t . Однако С#- и С++-структуры имеют кардинальноеотличие. В C++ тип s t r u c t — эти тип класса, причем типы s t r u c t и c l a s s практически эквивалентны (различие между ними выражается в доступе к их членам поумолчанию: для класса он принят закрытым, а для структуры — открытым).
В С#ключевое слово s t r u c t используется для определения типов значений, a c l a s s —ссылочных типов.-J ПеречисленияПеречисление (enumeration) — это множество именованных целочисленных констант. Ключевое слово enum объявляет перечислимый тип.
Формат записи перечисления таков:enum имя{список_перечисления);Здесь с помощью элемента имя указывается имя типа перечисления. Элемент список_перечисленияпредставляет собой список идентификаторов, разделенных запятыми.Рассмотрим пример. В следующем фрагменте кода определяется перечислениеapple, которое содержит список названий различных сортов яблок.Ienum apple{ Jonathan, GoldenDel, RedDel,Cortland, Mclntosh } ;Winsap,Здесь важно понимать, что каждый символ списка перечисления означает целоечисло, причем каждое следующее число (представленное идентификатором) на единицу больше предыдущего. Поскольку значение первого символа перечисления равнонулю, следовательно, идентификатор Jonathan имеет значение 0, GoldenDel — значение 1 и т.д.Константу перечисления можно использовать везде, где допустимо целочисленноезначение. Однако между типом enum и встроенным целочисленным типом неявныепреобразования не определены, поэтому при необходимости должна использоватьсяявно заданная операция приведения типов.
В случае преобразования одного типа перечисления в другой также необходимо использовать приведение типов.К членам перечисления доступ осуществляется посредством имени типа и оператора "точка". Например, при выполнении инструкцииI Console.WriteLine(apple.RedDel + " имеет значение " +I(int)apple.RedDel);будет отображено следующее.1 RedDel имеет значение 2Как подтверждает результат выполнения этой инструкции, при отображении значения перечислимого типа используется его имя. А для получения его целочисленногозначения необходимо использовать операцию приведения к типу i n t .
(В этом заключается отличие от ранних версий С#, в которых по умолчанию отображалось целочисленное представление значения перечислимого типа, а не его имя.)Теперь рассмотрим программу, которая демонстрирует использование перечисления apple.// Демонстрация использования перечисления.using System;class EnumDemo {Глава 12. Интерфейсы, структуры и перечисления345enum apple { Jonathan, GoldenDel, RedDel, Winsap,Cortland, Mclntosh };public static void Main() {string[] color = {"красный","желтый","красный","красный","красный","красно-зеленый"apple i; // Объявляем переменную перечислимого типа.// Используем переменную i для обхода всех// членов перечисления.for(i = apple.Jonathan; i <= apple.Mclntosh; i++)Console.WriteLine(i + " имеет значение " + (int)i);Console.WriteLine() ;// Используем перечисление для индексации массива.for(i = apple.Jonathan; i <= apple.Mclntosh; i++)Console.WriteLine("Цвет сорта " + i + " - " +color[(int)i]);Результаты выполнения этой программы таковы:Jonathan имеет значение ОGoldenDel имеет значение 1RedDel имеет значение 2Winsap имеет значение 3Cortland имеет значение 4Mclntosh имеет значение 5ЦветЦветЦветЦветЦветЦветсортасортасортасортасортасортаJonathan - красныйGoldenDel - желтыйRedDel - красныйWinsap - красныйCortland - красныйMclntosh - красно-зеленыйОбратите внимание на то, как for-циклы управляются переменной типа apple.Поскольку перечисление — это целочисленный тип, значение перечисления можетбыть использовано везде, где допустимы целые значения.
Поскольку значения перечислимого типа начинаются с нуля, их можно использовать для индексирования массива c o l o r (чтобы получить цвет яблок). Заметьте: в этом случае необходимо выполнить приведение типа. Как упоминалось выше, неявные преобразования между целочисленными и перечислимыми типами не определены. Поэтому без явно заданногоприведения типа здесь не обойтись.И еще. Поскольку перечислимые типы представляют собой целочисленные значения, их можно использовать для управления switch-инструкцией (соответствующийпример приведен ниже).346Часть I. Язык С#Инициализация перечисленийОдно или несколько символов в перечислении можно определить с помощью инициализатора. Это реализуется путем использования знака "равно" и последующегоцелого значения. Символам, стоящим после инициализатора, присваиваются значения, превышающие предыдущее значение инициализации.
Например, следующийфрагмент кода присваивает число 10 символу RedDel.enum apple { Jonathan, GoldenDel, RedDel = 10, Winsap,Cortland, Mclntosh };Вот какие значения имеют теперь эти символы:Jonathan0GoldenDelIRedDel10Winsap11Cortland12Mclntosh13IЗадание базового типа перечисленияПо умолчанию перечисления используют тип i n t , но можно также создать перечисление любого другого целочисленного типа, за исключением типа char. Чтобы задать тип, отличный от i n t , укажите этот базовый тип после имени перечисления идвоеточия.
Например, следующая инструкция создает перечисление apple с базовымтипом byte.enum apple : byte { Jonathan, GoldenDel> RedDel, Winsap,Cortland, Mclntosh };IТеперь член apple.Winsap, например, представляет собой byte-значение.Использование перечисленийНа первый взгляд может показаться, что перечисления, хотя и представляют определенный интерес, но вряд ли заслуживают большого внимания С#-программиста.Это не так. Перечисления незаменимы, когда в программе необходимо использоватьодин или несколько специализированных символов. Например, представьте, что выпишете программу для управления лентой конвейера на фабрике.
Вы могли бы создать метод conveyor (), который в качестве параметров принимает следующие параметры: старт, стоп, вперед и назад. Вместо того чтобы передавать методу conveyor ()числа (1 для команды "старт", 2 для команды "стоп" и т.д.), что чревато ошибками,вы можете создать перечисление, которое этим числам присваивает слова. Вот примерjaKoro решения:// Управление лентой конвейера.using System;c l a s s ConveyorControl {// Перечисляем команды, управляющие конвейером,p u b l i c enum a c t i o n { старт, стоп, вперед, назадp u b l i c void conveyor ( a c t i o n corn) {switch(com) {case a c t i o n . с т а р т :Console.WriteLine("Запуск конвейера.
") ;Глава 12. Интерфейсы, структуры и перечисления<};347break;case action.стоп:Console.WriteLine("Останов конвейера.");break;case action.вперед:Console.WriteLine("Перемещение вперед.");break;case action.назад:Console.WriteLine("Перемещение назад.");break;class ConveyorDemo {public s t a t i c void Main() {ConveyorControl с = new ConveyorControl()c.conveyor(ConveyorControl.action.старт);с.conveyor(ConveyorControl.action.вперед)с.conveyor(ConveyorControl.action.назад);с.conveyor(ConveyorControl.action.стоп);Вот какие результаты генерирует эта программа:Запуск конвейера.Перемещение вперед.Перемещение назад.Останов конвейера.Поскольку метод conveyor () принимает аргумент типа a c t i o n , этому методумогут передаваться только значения, имеющие тип a c t i o n .
Вот, например, попыткапередать методу conveyor () значение 22.I с.conveyor(22);// Ошибка!Эта инструкция нпе скомпилируется, поскольку встроенного преобразования из типа i n t в тип a c t i o n не существует. Это — своего рода защита от передачи методуconveyor () некорректных команд. Конечно, чтобы "настоять" на таком преобразовании, можно было бы использовать операцию приведения типов, но это потребовалобы заранее продуманных действий и вряд ли привело к случайной ошибке.