C# 4.0 полное руководство - 2011
Шрифт:
Далее в классе 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); // задать начальное значение
}
//Реализовать
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;
}
public void Reset {
val = start;
}
public void SetStart(T v) { start = v; val = start;
}
}
class ThreeD {
public int x/ч у, z;
public ThreeD(int a, int b, int c) { x = a;
У = b;
z = c;
}
}
class GenlntfDemo {
// Определить метод увеличения на два каждого // последующего значения типа int. static int IntPlusTwo(int v) { return v + 2;
}
// Определить метод увеличения на два каждого // последующего значения типа double, static double DoublePlusTwo(double v) { return v + 2.0;
}
// Определить метод увеличения на два каждого // последующего значения координат объекта типа ThreeD. static ThreeD ThreeDPlusTwo(ThreeD v) { if(v==null) return new ThreeD(0, 0, 0) ; else return new ThreeD(v.x + 2, v.y + 2, v.z + 2);
}
static void Main {
// Продемонстрировать генерирование // последовательного ряда значений типа int. ByTwos<int> intBT = new ByTwos<int>(IntPlusTwo);
for(int i=0; i < 5; i++)
Console.Write(intBT.GetNext + " ") ;
Console.WriteLine;
// Продемонстрировать генерирование // последовательного ряда значений типа double. ByTwos<double> dblBT =
new ByTwos<double>(DoublePlusTwo); dblBT.SetStart(11.4);
for(int i=0; i < 5; i++)
Console.Write(dblBT.GetNext + " ");
Console.WriteLine;