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