Г. Шилдт - С#4.0 Полное руководство (1160795), страница 115
Текст из файла (страница 115)
Ограничение типа значения является дополнением ограничения ссылочного типа. Оно просто гарантирует, что любой аргумент, обозначающий тип, должен быть типа значения, в том числе зсгпсс и епипь (В данном случае обнуляемый тип не относится к типу значения.) Ниже приведен пример наложения ограничения типа значения. Продемонстрировать наложение ограничения типа значения.
азгпу Яузгеи; асгосс Музсгпсс ( уу... ) с1азз МуС1азз ( О ) с1азз теаь<т> вьете т : зггосг ( Т оЬ)г роЬ11с Тезг(Т х) ( оЬ) = х; ) с1азз Ча1оеСопвггаьпгэеио *Ьас1с чогг) Маьп() ( О Оба следухзмх объявления вполне допустимы. тезс<муяьгпсг> х = пем тезь<муяггось>(пеи муясгись()) 602 Часть ). язык СФ тевс<1пс> у = пен тевс<1пс>(10)г г/ А следуюцее объявление недопустимо! /г' тевс<мус1ввв> в = лен тввс<мус1ввв>(пвн мус1авв()); ) ) В этом примере кода класс Те в С объявляется следующим образом.
с1ввв Тввг<Т> вьете Т : вггссв ( На параметр типа т в классе тевс накладывается ограничение всгисс, и поэтому к нему могут быть привязаны только аргументы типа значения. Это означает, что объявления Тевг<иуэггпсг>,и Тевг<1пг> вполне допустимы, тогда как объявление Те в с<муС1ав в > недопустимо. Для того чтобы убедиться в этом, удалите символы комментария в начале последней строки приведенного выше кода и перекомпилируйте его. В итоге вы получите сообщение об ошибке во время компиляции. Установление связи между двумя параметрами типа с помощью ограничения Существует разновидность ограничения на базовый класс, позволяющая установить связь между двумя параметрами типа. В качестве примера рассмотрим следующее объявление обобщенного класса.
с1авв Беп<Т, Ч> вьете Ч : Т ( В этом объявлении оператор мбеге уведомляет компилятор о том, что аргумент типа, привязанный к параметру типа Ч, должен быть таким же, как и аргумент типа, привязанный к параметру типа Т, или же наследовать от него. Если подобная связь отсутствует при объявлении объекта типа сеп, то во время компиляции возникнет ошибка. Такое ограничение на параметр типа называется неприкрмпгмм ограничением п)ила. В приведенном ниже примере демонстрируется наложение этого ограничения. г! установить связь между двумя параметрами типа. овтпс Бувгевв с1авв А ( ) с1авв В: А ( О ) Здесь параметр типа Ч должен наследовать от параметра типа Т.
с1авв Сеп<Т, Ч> вьете Ч : Т ( О ) с1авв НаьеССопввгазпвбето ( вваотс чогб Маги() ( Зто объявление вполне допустимо, поскольку Глава 18. Обобщения 603 О класс В наследует от класса А. Сел<А, В> х = пеи Сел<А, В>(); /! А это объявление недопустимо, поскольку О класс А -не наследует от класса В. // Сел<В, А> у = пеи Сел<В, А>()г Обратите внимание на то, что класс В наследует от класса А. Проанализируем далее оба объявления объектов класса Сеп в методе Магп () .
Как следует из комментария к первому объявлению Сеп<А, В> х = пеи Сеп<А, В>(); оно вполне допустимо, поскольку класс В наследует от класса А. Но второе объявление // Сел<В, А> у = пеи Сел<В, А>()," недопустимо, поскольку класс А не наследует от класса В. Применение нескольких ограничений С параметром типа может быть связано несколько ограничений. В этом случае ограничения указываются списком через запятую. В этом списке первым должно быть указано ограничение с1аяя либо ясгпсс, если оно присутствует, или же ограничение на базовый класс, если оно накладывается. Указывать ограничения с1аз з или я Сгпсг одновременно с ограничением на базовый класс не разрешается.
Далее по списку должно следовать ограничение на интерфейс, а последним по порядку — ограничение пеи () . Например, следующее объявление считается вполне допустимым. с1аяя Сеп<Т> иьеге Т : МуС1азя, 1МУ1пгегтасе, пеи() ( О В данном случае параметр типа Т должен быть заменен аргументом типа, наследующим от класса МУС1азз, реализующим интерфейс 1Му1пгеггасе и использующим конструктор без параметра.
Если же в обобщении используются два или более параметра типа, то ограничения на каждый из них накладываются с помощью отдельного оператора и)гете, как в приведенном ниже примере. // Использовать несколько операторов инесе. пя1по Яуясещг // У класса Сеп имеются два параметра типа, и на оба накладываются ограничения с помощью отдельных операторов иЛеге. с1аяя Сеп<Т, Ч> и)гете Т : с1азя исеге Ч : я<гесс ( Т оЫ~ Ч ос2; рпЫгс Сеп(Т С, Ч ч) оЫ 604 Часть!. Язык С№ оЪ2 = н1 ) ) с1аяв мп1с1р1есппяг та1псэепю ( япаьтс хогг( Маьп() ( Эта строка кода вполне допустима, поскольку ясх1пд — этп ссылпчный тип, а тпс — тип значения.
Пеп<впгьпд, тпс> оЬЗ = пеи Пеп<впгьпэ, ьпг>("тест", 11) О А следукмая строка кода недопустима, поскольку // Ьоо1 не относится к ссылпчнпму типу. О Оеп<Ьпп1, ьпп> пЬ1 = пен оеп<Ьпп1, ьпс>[гхпе, 11); ) ) В данном примере класс реп принимает два аргумента с ограничениями, накладываемыми с помощью отдельных операторов ыпеге. Обратите особое внимание на объявление этого класса. <1аяв Пеп<Т, У> маете Т : с1аяв нвеге у : зпгпсг Как видите, один оператор мпеге отделяется от другого только пробелом. Другие знаки препинания мея<ду ними не нужны и даже недопустимы. Получение значения, присваиваемого параметру типа по умолчанию Как упоминалось выше, при написании обобщенного кода иногда важно провести различие между типами значений и ссылочными типами.
Такая потребность возникает, в частности, в том случае, если переменной параметра типа должно быть присвоено значение по умолчанию. Для ссылочных типов значением по умолчанию является пи11, для неструктурных типов значений — О или логическое значение Га1ве, если это тип Ьоо1, а для структур типа з Ь гпс С вЂ” объект соответствующей структуры с полями, установленными по умолчанию. В этой связи возникает вопрос какое значение следует присваивать по умолчанию переменной параметра типа: пп11, О или нечто другое? Например, если в следующем объявлении класса Теат: с1авв Теяг<Т> ( Т оЬЗ1 О переменной оЬЗ требуется присвоить значение по умолчанию, то какой из двух вариантов пЬЗ = пп11; // подходит только для ссылочных типов или пЬ1 = 0; // подходит только лля числовых типов и перечислений, на не для структур следует выбрать? Для разрешения этой дилеммы можно воспользоваться еще одной формой оператора с(етап1С, приведенной ниже.
Глава 18. Обобщения 605 бесао1С(тип) Эта форма оператора беТаи1С пригодна длд всех аргументов типа, будь то типы значений или ссылочные типы. Ниже приведен короткий пример, демонстрирующий данную форму оператора бебап1Ь. Продемонстрировать форму оператора бегао1с. оа1пд Бувсешг с1авв МуС1авя ( //... ) Получить значение, присваиваемое параметру типа Т по умолчанию. с1авя Теяо<Т> ( роЬ11с Т оЪ)г роЬ11с Тевг() ( // Следуюший оператор годится только для ссылочных типов. // оЬО = по11г // не годится Слелукший оператор годится только для типов значений.
// оЬО = Ог // не годится // () этот оператор годится как для ссылочных типов, так и для типов значений. оЬО = бегао1с(Т)г // годится! с1аяв Оетао1тоешо ( яоаогс тога Ма1п() ( // Сконструировать объект класса Теяп, используя ссылочный тип. Теяг<нуС1аяя> х = пен Тевс<муС1авв>()) гс(х.оЬО == по11) Сопяо1е.нгггеЬТпе("Переменная х.оЬО имеет пустое значение <по11>.") // Сконструировать объект класса Тевг, используя тип значения. Теяо<гпо> у = пен Теяо<1по>()г ТГ(у.оЬ) == О) Сопво1е.иггсеЬТпе("Перемвнная у.оЬ1 имеет значение О.") ) Вот к какому результату приводит выполнение этого кода. Переменная х.оЬО имеет пустое значение <по11>.
Переменная у.оЬО имеет значение О. 606 Часть (. Язык С() Обобщенные структуры В СФ разрешается создавать обобщенные структуры. Синтаксис для них такой же, как и для обобщенных классов. В качестве примера ниже приведена программа, в которой создается обобщенная структура ХХ для хранения координат Х, 'х'. // Продемонстрировать применение обобщенной структуры. овьп9 эуявещ; Эта структура является обобщенной. вссесС ХХ<т> ( Т х; ту; рпЬ11с ХХ(т а, т Ы ( х= а; у =ь; ) роЬ1ьс Т Х ( чеС ( тевотп х; яес ( х = ча1ое; ] ) роЫ1с Т Х ( чес ( тесотп у; ) яеС ( у = ча1пе) ) ) с1авя 8СснсСТеяС ( всас1с чохб Маха() ( ХХ<тпС> ху = пен ХХ<зпС>(10, 20); ХХ<бонЫе> ху2 = пем ХХ<доиЫе>(88.0, 99.0): Сопяо1е.нх1Севтпе(ху.Х + ", " + ху.Х); Сопяо1е.нсьтевтпе(ху2.Х + ", " + ху2.Х); При выполнении этой программы получается следующий результат.
10, 20 88, 99 Как и на обобщенные классы, на обобщенные сгруктуры могут накладываться ограничения. Например, на аргументы типа в приведенном ниже варианте структуры ХХ накладывается ограничение типа значения. яссосс хх<т> мнете т : всснсс ( // Глава 18. Обобщения 607 Создание обобщенного метода Как следует из приведенных выше примеров, в методах, объявляемых в обобщенных классах, может использоваться параметр типа из данного класса, а следовательно, такие методы автоматически становятся обобщенными по отношению к параметру типа. Но помимо этого имеется возможность объявить обобщенный метод со своими собственными параметрами типа и даже создать обобщенный метод, заключенный в необобщенном классе. Рассмотрим для начала простой пример.