Категории
ТОП за месяц
onlinekniga.com » Компьютеры и Интернет » Программирование » Полное руководство. С# 4.0 - Шилдт Герберт

Полное руководство. С# 4.0 - Шилдт Герберт

Читать онлайн Полное руководство. С# 4.0 - Шилдт Герберт

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 124 125 126 127 128 129 130 131 132 ... 188
Перейти на страницу:

Далее проанализируем приведенный ниже конструктор класса Test.public Test() { // Этот код работоспособен благодаря наложению ограничения new(). obj = new Т(); // создать объект типа Т}

В этом фрагменте кода создается объект типа Т, и ссылка на него присваиваетсяпеременной экземпляра obj. Такой код допустим только потому, что ограничениеnew() требует наличия конструктора. Для того чтобы убедиться в этом, попробуйтесначала удалить ограничение new(), а затем попытайтесь перекомпилировать программу. В итоге вы получите сообщение об ошибке во время компиляции.

В методе Main() получается экземпляр объекта типа Test, как показано ниже.Test<MyClass> х = new Test<MyClass>();

Обратите внимание на то, что аргументом типа в данном случае является классMyClass и что в этом классе определяется конструктор без параметров. Следовательно, этот класс допускается использовать в качестве аргумента типа для класса Test.Следует особо подчеркнуть, что в классе MyClass совсем не обязательно определятьконструктор без параметров явным образом. Его используемый по умолчанию конструктор вполне удовлетворяет накладываемому ограничению. Но если классу потребуются другие конструкторы, помимо конструктора без параметров, то придетсяобъявить явным образом и вариант без параметров.

Что касается применения ограничения new(), то следует обратить внимание натри других важных момента. Во-первых, его можно использовать вместе с другимиограничениями, но последним по порядку. Во-вторых, ограничение new() позволяетконструировать объект, используя только конструктор без параметров, — даже еслидоступны другие конструкторы. Иными словами, передавать аргументы конструкторупараметра типа не разрешается. И в-третьих, ограничение new() нельзя использоватьодновременно с ограничением типа значения, рассматриваемым далее.Ограничения ссылочного типа и типа значения

Два других ограничения позволяют указать на то, что аргумент, обозначающий тип,должен быть либо ссылочного типа, либо типа значения. Эти ограничения оказываются полезными в тех случаях, когда для обобщенного кода важно провести различиемежду ссылочным типом и типом значения. Ниже приведена общая форма ограничения ссылочного типа.where Т : class

В этой форме с оператором where ключевое слово class указывает на то, что аргумент Т должен быть ссылочного типа. Следовательно, всякая попытка использоватьтип значения, например int или bool, вместо Т приведет к ошибке во время компиляции.

Ниже приведена общая форма ограничения типа значения.where Т : struct

В этой форме ключевое слово struct указывает на то, что аргумент Т должен бытьтипа значения. (Напомним, что структуры относятся к типам значений.) Следовательно, всякая попытка использовать ссылочный тип, например string, вместо T приведетк ошибке во время компиляции. Но если имеются дополнительные ограничения, тов любом случае class или struct должно быть первым по порядку накладываемымограничением.

Ниже приведен пример, демонстрирующий наложение ограничения ссылочноготипа.// Продемонстрировать наложение ограничения ссылочного типа.using System;class MyClass { // ...}// Наложить ограничение ссылочного типа.class Test<T> where Т : class { Т obj; public Test() { // Следующий оператор допустим только потому, что // аргумент Т гарантированно относится к ссылочному // типу, что позволяет присваивать пустое значение. obj = null; } // ...}class ClassConstraintDemo { static void Main() { // Следующий код вполне допустим, поскольку MyClass является классом. Test<MyClass> х = new Test<MyClass>(); // Следующая строка кода содержит ошибку, поскольку // int относится к типу значения. // Test<int> у = new Test<int>(); }}

Обратите внимание на следующее объявление класса Test.class Test<T> where T : class {

Ограничение class требует, чтобы любой аргумент Т был ссылочного типа. В данном примере кода это необходимо для правильного выполнения операции присваивания в конструкторе класса Test.public Test() { // Следующий оператор допустим только потому, что // аргумент Т гарантированно относится к ссылочному // типу, что позволяет присваивать пустое значение. obj = null;}

В этом фрагменте кода переменной obj типа T присваивается пустое значение. Такое присваивание допустимо только для ссылочных типов. Как правило, пустое значение нельзя присвоить переменной типа значения. (Исключением из этого правилаявляется обнуляемый тип, который представляет собой специальный тип структуры,инкапсулирующий тип значения и допускающий пустое значение (null). Подробнееоб этом — в главе 20.) Следовательно, в отсутствие ограничения такое присваиваниебыло бы недопустимым, и код не подлежал бы компиляции. Это один из тех случаев,когда для обобщенного кода может оказаться очень важным различие между типамизначений и ссылочными типами.

Ограничение типа значения является дополнением ограничения ссылочного типа.Оно просто гарантирует, что любой аргумент, обозначающий тип, должен быть типазначения, в том числе struct и enum. (В данном случае обнуляемый тип не относитсяк типу значения.) Ниже приведен пример наложения ограничения типа значения.// Продемонстрировать наложение ограничения типа значения.using System;struct MyStruct { // ...}class MyClass { // ...}class Test<T> where T : struct { T obj; public Test(T x) { obj = x; } // ...}class ValueConstraintDemo { static void Main() { // Оба следующих объявления вполне допустимы. Test<MyStruct> х = new Test<MyStruct>(new MyStruct()); Test<int> у = new Test<int>(10); // А следующее объявление недопустимо! // Test<MyClass> z = new Test<MyClass>(new MyClass()); }}

В этом примере кода класс Test объявляется следующим образом.class Test<T> where Т : struct {

На параметр типа Т в классе Test накладывается ограничение struct, и поэтому к нему могут быть привязаны только аргументы типа значения. Это означает, чтообъявления Test и Test вполне допустимы, тогда как объявлениеTest недопустимо. Для того чтобы убедиться в этом, удалите символы комментария в начале последней строки приведенного выше кода и перекомпилируйтеего. В итоге вы получите сообщение об ошибке во время компиляции.Установление связи между двумя параметрами типа с помощью ограничения

Существует разновидность ограничения на базовый класс, позволяющая установитьсвязь между двумя параметрами типа. В качестве примера рассмотрим следующееобъявление обобщенного класса.class Gen<T; V> where V : T {

В этом объявлении оператор where уведомляет компилятор о том, что аргументтипа, привязанный к параметру типа V, должен быть таким же, как и аргумент типа,привязанный к параметру типа Т, или же наследовать от него. Если подобная связьотсутствует при объявлении объекта типа Gen, то во время компиляции возникнетошибка. Такое ограничение на параметр типа называется неприкрытым ограничениемтипа. В приведенном ниже примере демонстрируется наложение этого ограничения.// Установить связь между двумя параметрами типа.using System;class А { // ...}class В : А { // ...}// Здесь параметр типа V должен наследовать от параметра типа Т.class Gen<T, V> where V : T { // ...}class NakedConstraintDemo { static void Main() { // Это объявление вполне допустимо, поскольку // класс В наследует от класса А. GerKA, В> х = new Gen<A, В>(); // А это объявление недопустимо, поскольку // класс А не наследует от класса В. // Gen<B, А> у = new Gen<B, А>(); }}

Обратите внимание на то, что класс В наследует от класса А. Проанализируем далееоба объявления объектов класса Gen в методе Main(). Как следует из комментарияк первому объявлениюGen<A, В> х = new Gen<A, В>();

оно вполне допустимо, поскольку класс В наследует от класса А. Но второе объявление// Gen<B, А> у = new Gen<B, А>();

недопустимо, поскольку класс А не наследует от класса В.Применение нескольких ограничений

С параметром типа может быть связано несколько ограничений. В этом случаеограничения указываются списком через запятую. В этом списке первым должно бытьуказано ограничение class либо struct, если оно присутствует, или же ограничениена базовый класс, если оно накладывается. Указывать ограничения class или structодновременно с ограничением на базовый класс не разрешается. Далее по спискудолжно следовать ограничение на интерфейс, а последним по порядку — ограничениеnew(). Например, следующее объявление считается вполне допустимым.class Gen<T> where Т : MyClass, IMyInterface, new() { // ...

1 ... 124 125 126 127 128 129 130 131 132 ... 188
Перейти на страницу:
На этой странице вы можете бесплатно читать книгу Полное руководство. С# 4.0 - Шилдт Герберт.
Комментарии