}
Эта программа дает следующий результат.
6
тевирП
Рассмотрим эту программу более подробно. Прежде всего обратите внимание на следующее объявление делегата SomeOp.
delegate Т SomeOp<T>(T v);
Как видите, тип Т может служить в качестве возвращаемого типа, несмотря на то, что параметр типа Т указывается после имени делегата SomeOp.
Далее в классе GenDelegateDemo объявляются методы Sum () и Reflect (), как показано ниже.
static int Sum(int v) {
static string Reflect(string str) {
Метод Sum () возвращает результат суммирования целого значения, передаваемого в качестве аргумента, а метод Reflect () — символьную строку, которая получается обращенной по отношению к строке, передаваемой в качестве аргумента.
В методе Main () создается экземпляр intDel делегата, которому присваивается ссылка на метод Sum ().
SomeOp<int> intDel = Sum;
Метод Sum () принимает аргумент типа int и возвращает значение типа int, поэтому он совместим с целочисленным экземпляром делегата SomeOp.
Аналогичным образом создается экземпляр strDel делегата, которому присваивается ссылка на метод Reflect ().
SomeOp<string> strDel = Reflect;
Метод Reflect () принимает аргумент типа string и возвращает результат типа string, поэтому он совместим со строковым экземпляром делегата SomeOp.
В силу присущей обобщениям типовой безопасности обобщенным делегатам нельзя присваивать несовместимые методы. Так, следующая строка кода оказалась бы ошибочной в рассматриваемой здесь программе.
Ведь метод Reflect () принимает аргумент типа string и возвращает результат типа string, а следовательно, он несовместим с целочисленным экземпляром делегата SomeOp.
Обобщенные интерфейсы
Помимо обобщенных классов и методов, в C# допускаются обобщенные интерфейсы. Такие интерфейсы указываются аналогично обобщенным классам. Ниже приведен измененный вариант примера из главы 12, демонстрирующего интерфейс ISeries. (Напомним, что ISeries является интерфейсом для класса, генерирующего последовательный ряд числовых значений.) Тип данных, которым оперирует этот интерфейс, теперь определяется параметром типа.
// Продемонстрировать применение обобщенного интерфейса, using System;
public interface ISeries<T> {
T GetNext();// возвратить следующее по порядку число
void Reset(); // генерировать ряд последовательных чисел с самого начала void SetStart(T v); // задать начальное значение
}
//Реализовать интерфейс ISeries, class ByTwos<T> : ISeries<T> {
T start;
T val;
// Этот делегат определяет форму метода, вызываемого для генерирования // очередного элемента в ряду последовательных значений, public delegate Т IncByTwo(Т v);
// Этой ссылке на делегат будет присвоен метод,
// передаваемый конструктору класса ByTwos.
IncByTwo incr;
public ByTwos(IncByTwo incrMeth) { start = default(T); val = default(T); incr = incrMeth;
}
public T GetNext() { val = incr(val); return val;
