Чтение онлайн

на главную - закладки

Жанры

Полное руководство. С# 4.0
Шрифт:

Ниже приведен пример, демонстрирующий ковариантность и контравариант ность. // Продемонстрировать ковариантность и контравариантность. using System; class X { public int Val; } // Класс Y, производный от класса X. class Y : X { } // Этот делегат возвращает объект класса X и // принимает объект класса Y в качестве аргумента. delegate X ChangeIt(Y obj); class CoContraVariance { // Этот метод возвращает объект класса X и // имеет объект класса X в качестве параметра. static X IncrA(X obj) { X temp = new X; temp.Val = obj.Val + 1; return temp; } // Этот метод возвращает объект класса Y и // имеет объект класса Y в качестве параметра. static Y IncrB(Y obj) { Y temp = new Y; temp.Val = obj.Val + 1; return temp; } static void Main { Y Yob = new Y; //

В данном случае параметром метода IncrA является объект класса X, // а параметром делегата ChangeIt — объект класса Y. Но благодаря // контравариантности следующая строка кода вполне допустима. Changelt change = IncrA; X Xob = change(Yob); Console.WriteLine("Xob: " + Xob.Val); // В этом случае возвращаемым типом метода IncrB служит объект класса Y, // а возвращаемым типом делегата ChangeIt — объект класса X. Но благодаря // ковариантности следующая строка кода оказывается вполне допустимой. change = IncrB; Yob = (Y) change (Yob); Console.WriteLine("Yob: " + Yob.Val); } }

Вот к какому результату приводит выполнение этого кода. Xob: 1 Yob: 1

В данном примере класс Y является производным от класса X. А делегат ChangeIt объявляется следующим образом. delegate X ChangeIt(Y obj);

Делегат возвращает объект класса X и принимает в качестве параметра объект клас са Y. А методы IncrA и IncrB объявляются следующим образом. static X IncrA(X obj) static Y IncrB(Y obj)

Метод IncrA принимает объект класса X в качестве параметра и возвращает объект того же класса. А метод IncrB принимает в качестве параметра объект клас са Y и возвращает объект того же класса. Но благодаря ковариантности и контравари антности любой из этих методов может быть передан делегату ChangeIt, что и демон стрирует рассматриваемый здесь пример.

Таким образом, в строке ChangeIt change = IncrA;

метод IncrA может быть передан делегату благодаря контравариантности, так как объект класса X служит в качестве параметра метода IncrA, а объект класса Y — в качестве параметра делегата ChangeIt. Но метод и делегат оказываются совмести мыми в силу контравариантности, поскольку типом параметра метода, передаваемого делегату, служит класс, являющийся базовым для класса, указываемого в качестве типа параметра делегата.

Приведенная ниже строка кода также является вполне допустимой, но на этот раз благодаря ковариантности. change = IncrB;

В данном случае возвращаемым типом для метода IncrB служит класс Y, а для делегата — класс X. Но поскольку возвращаемый тип метода является производным классом от возвращаемого типа делегата, то оба оказываются совместимыми в силу ковариантности. Класс System.Delegate

Все делегаты и классы оказываются производными неявным образом от класса System.Delegate. Как правило, членами этого класса не пользуются непосред ственно, и это не делается явным образом в данной книге. Но члены класса System. Delegate могут оказаться полезными в ряде особых случаев. Назначение делегатов

В предыдущих примерах был наглядно продемонстрирован внутренний механизм действия делегатов, но эти примеры не показывают их истинное назначение. Как пра вило, делегаты применяются по двум причинам. Во-первых, как упоминалось ранее в этой главе, делегаты поддерживают события. И во-вторых, делегаты позволяют вы зывать методы во время выполнения программы, не зная о них ничего определенно го в ходе компиляции. Это очень удобно для создания базовой конструкции, допу скающей подключение отдельных программных компонентов. Рассмотрим в качестве примера графическую программу, аналогичную стандартной сервисной программе Windows Paint. С помощью делегата можно предоставить пользователю возможность подключать специальные цветные фильтры или анализаторы изображений. Кроме того, пользователь может составлять из этих фильтров или анализаторов целые по следовательности. Подобные возможности программы нетрудно обеспечить, исполь зуя делегаты. Анонимные функции

Метод, на который ссылается делегат, нередко используется только для этой цели. Иными словами, единственным основанием для существования метода служит то об стоятельство, что он может быть вызван посредством делегата, но сам он не вызывается вообще. В подобных случаях можно воспользоваться анонимной функцией, чтобы не создавать отдельный метод. Анонимная функция, по существу, представляет собой безымянный кодовый блок, передаваемый конструктору делегата. Преимущество ано нимной функции состоит, в частности, в ее простоте. Благодаря ей отпадает необходи мость объявлять отдельный метод, единственное назначение которого состоит в том, что он передается делегату.

Начиная с версии 3.0, в C# предусмотрены две разновидности анонимных функ ций: анонимные методы и лямбда-выражения. Анонимные методы были внедрены в C# еще в версии 2.0, а лямбда-выражения — в версии 3.0. В целом лямбда-выражение со вершенствует принцип действия анонимного метода и в настоящее время считается более предпочтительным для создания анонимной функции. Но анонимные методы широко применяются в существующем коде С# и поэтому по-прежнему являются важной составной частью С#. А поскольку анонимные методы предшествовали по явлению лямбда-выражений, то ясное представление о них позволяет лучше понять особенности лямбда-выражений. К тому же анонимные методы могут быть использо ваны в целом ряде случаев, где применение лямбда-выражений оказывается невозмож ным. Именно поэтому в этой главе рассматриваются и анонимные методы, и лямбда- выражения. Анонимные методы

Анонимный метод — один из способов создания безымянного блока кода, связан ного с конкретным экземпляром делегата. Для создания анонимного метода достаточ но указать кодовый блок после ключевого слова delegate. Покажем, как это делается, на конкретном примере. В приведенной ниже программе анонимный метод служит для подсчета от 0 до 5. // Продемонстрировать применение анонимного метода. using System; // Объявить тип делегата. delegate void CountIt; class AnonMethDemo { static void Main { // Далее следует код для подсчета чисел, передаваемый делегату // в качестве анонимного метода. CountIt count = delegate { // Этот кодовый блок передается делегату. for(int i=0; i <= 5; i++) Console.WriteLine(i); }; // обратите внимание на точку с запятой count; } }

В данной программе сначала объявляется тип делегата CountIt без параметров и с возвращаемым типом void. Далее в методе Main создается экземпляр count делегата CountIt, которому передается кодовый блок, следующий после ключевого слова delegate. Именно этот кодовый блок и является анонимным методом, кото рый будет выполняться при обращении к делегату count. Обратите внимание на то, что после кодового блока следует точка с запятой, фактически завершающая оператор объявления. Ниже приведен результат выполнения данной программы. 0 1 2 3 4 5 Передача аргументов анонимному методу

Анонимному методу можно передать один или несколько аргументов. Для этого достаточно указать в скобках список параметров после ключевого слова delegate, а при обращении к экземпляру делегата — передать ему соответствующие аргумен ты. В качестве примера ниже приведен вариант предыдущей программы, измененный с целью передать в качестве аргумента конечное значение для подсчета. // Продемонстрировать применение анонимного метода, принимающего аргумент. using System; // Обратите внимание на то, что теперь у делегата CountIt имеется параметр. delegate void CountIt (int end); class AnonMethDemo2 { static void Main { // Здесь конечное значение для подсчета передается анонимному методу. CountIt count = delegate (int end) { for(int i=0; i <= end; i++) Console.WriteLine(i); }; count(3); Console.WriteLine; count(5); } }

Поделиться:
Популярные книги

Жребий некроманта 2

Решетов Евгений Валерьевич
2. Жребий некроманта
Фантастика:
боевая фантастика
6.87
рейтинг книги
Жребий некроманта 2

Вперед в прошлое 6

Ратманов Денис
6. Вперед в прошлое
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Вперед в прошлое 6

Архил...? Книга 2

Кожевников Павел
2. Архил...?
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Архил...? Книга 2

Чемпион

Демиров Леонид
3. Мания крафта
Фантастика:
фэнтези
рпг
5.38
рейтинг книги
Чемпион

Назад в СССР 5

Дамиров Рафаэль
5. Курсант
Фантастика:
попаданцы
альтернативная история
6.64
рейтинг книги
Назад в СССР 5

Я граф. Книга XII

Дрейк Сириус
12. Дорогой барон!
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Я граф. Книга XII

Матабар

Клеванский Кирилл Сергеевич
1. Матабар
Фантастика:
фэнтези
5.00
рейтинг книги
Матабар

Титан империи 3

Артемов Александр Александрович
3. Титан Империи
Фантастика:
фэнтези
попаданцы
5.00
рейтинг книги
Титан империи 3

Темный Охотник

Розальев Андрей
1. КО: Темный охотник
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Темный Охотник

Вираж бытия

Ланцов Михаил Алексеевич
1. Фрунзе
Фантастика:
героическая фантастика
попаданцы
альтернативная история
6.86
рейтинг книги
Вираж бытия

Мастер Разума II

Кронос Александр
2. Мастер Разума
Фантастика:
героическая фантастика
попаданцы
аниме
5.75
рейтинг книги
Мастер Разума II

Кодекс Охотника. Книга VII

Винокуров Юрий
7. Кодекс Охотника
Фантастика:
фэнтези
попаданцы
аниме
4.75
рейтинг книги
Кодекс Охотника. Книга VII

Большие дела

Ромов Дмитрий
7. Цеховик
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Большие дела

Я тебя верну

Вечная Ольга
2. Сага о подсолнухах
Любовные романы:
современные любовные романы
эро литература
5.50
рейтинг книги
Я тебя верну