Студопедия

Главная страница Случайная страница

Разделы сайта

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника






Универсальные делегаты






Делегаты также могут иметь родовые параметры. Чаще встречается ситуация, когда делегат объявляется в универсальном классе и использует в своем объявлении параметры универсального класса. Давайте рассмотрим ситуацию с делегатами более подробно. Вот объявление универсального класса, не очень удачно названного Delegate, в котором объявляется функциональный тип - delegate:

class Delegate< T> { public delegate T Del(T a, T b); }

Как видите, тип аргументов и возвращаемого значения в сигнатуре функционального типа определяется классом Delegate.

Добавим в класс функцию высшего порядка FunAr, одним из аргументов которой будет функция типа Del, заданного делегатом. Эта функция будет применяться к элементам массива, передаваемого также функции FunAr. Приведу описание:

public T FunAr(T[] arr, T a0, Del f){ T temp = a0; for(int i =0; i< arr.Length; i++) { temp = f(temp, arr[i]); } return (temp); }

Эта универсальная функция с успехом может применяться для вычисления сумм, произведения, минимума и других подобных характеристик массива.

Рассмотрим теперь клиентский класс Testing, в котором определен набор функций:

public int max2(int a, int b) { return (a > b)? a: b; }public double min2(double a, double b) { return (a < b)? a: b; }public string sum2(string a, string b) { return a + b; }public float prod2(float a, float b) { return a * b; }

Хотя все функции имеют разные типы, все они соответствуют определению класса Del - имеют два аргумента одного типа и возвращают результат того же типа. Посмотрим, как они применяются в тестирующем методе класса Testing:

public void TestFun(){ int[] ar1 = { 3, 5, 7, 9 }; double[] ar2 = { 3.5, 5.7, 7.9 }; string[] ar3 = { " Мама ", " мыла ", " Машу ", " мылом." }; float[] ar4 = { 5f, 7f, 9f, 11f }; Delegate< int> d1 = new Delegate< int> (); Delegate< int>.Del del1; del1= this.max2; int max = d1.FunAr(ar1, ar1[0], del1); Console.WriteLine(" max= {0}", max); Delegate< double> d2 = new Delegate< double> (); Delegate< double>.Del del2; del2 = this.min2; double min = d2.FunAr(ar2, ar2[0], del2); Console.WriteLine(" min= {0}", min); Delegate< string> d3 = new Delegate< string> (); Delegate< string>.Del del3; del3 = this.sum2; string sum = d3.FunAr(ar3, " ", del3); Console.WriteLine(" concat= {0}", sum); Delegate< float> d4 = new Delegate< float> (); Delegate< float>.Del del4; del4 = this.prod2; float prod = d4.FunAr(ar4, 1f, del4); Console.WriteLine(" prod= {0}", prod); }

Обратите внимание на объявление экземпляра делегата:

Delegate< int>.Del del1;

В момент объявления задается фактический тип, и сигнатура экземпляра становится конкретизированной. Теперь экземпляр можно создать и связать с конкретной функцией. В C# 2.0 это делается проще и естественнее, чем ранее, - непосредственным присваиванием:

del1= this.max2;

При выполнении этого присваивания производятся довольно сложные действия - проверяется соответствие сигнатуры функции в правой части и экземпляра делегата, в случае успеха создается новый экземпляр делегата, который и связывается с функцией.

Покажем, что и сам функциональный тип-делегат можно объявлять с родовыми параметрами. Вот пример такого объявления:

public delegate T FunTwoArg< T> (T a, T b);

Добавим в наш тестовый пример код, демонстрирующий работу с этим делегатом:

FunTwoArg< int> mydel; mydel = max2; max = mydel(17, 21); Console.WriteLine(" max= {0}", max);

Вот как выглядят результаты работы тестового примера:


Рис. 22.7. Результаты работы с универсальными делегатами

Универсальные делегаты с успехом используются при определении событий. В частности, класс EventHandler, применяемый для всех событий, не имеющих собственных аргументов, теперь дополнен универсальным аналогом, определенным следующим образом:

public void delegate EventHandler< T> (object sender, T args) where T: EventArgs

Этот делегат может применяться и для событий с собственными аргументами, поскольку вместо параметра T может быть подставлен конкретный тип - потомок класса EventArgs, дополненный нужными аргументами.






© 2023 :: MyLektsii.ru :: Мои Лекции
Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав.
Копирование текстов разрешено только с указанием индексируемой ссылки на источник.