// Обратите внимание, теперь здесь имеется ограничение,

// требующее конструктор по умолчанию.

public class MyList‹T› where T: new() {

 private List‹T› listOfData = new List‹T›();

 public virtual void PrintList(T data) {}

 // Производный тип должен учитывать ограничения базового.

 public class MyReadOnlyList‹T›: MyList‹T› where T: new() {

  public override void PrintList(T data) {}

}

Если вы только не планируете построить свою собственную библиотеку обобщений, вероятность того, что вам придется строить иерархии обобщенных классов, оказывается практически нулевой. Тем не менее, вы теперь знаете, что язык C# обеспечивает поддержку наследования обобщений.

<p>Создание обобщенных интерфейсов</p>

Вы уже видели при рассмотрении пространства имен System.Collections. Generiс, что обобщенные интерфейсы в C# также допустимы (например, IEnumerable‹Т›). Вы, конечно, можете определить свои собственные обобщенные интерфейсы (как с ограничениями, так и без ограничений). Предположим, что нужно определить интерфейс, который сможет выполнять бинарные операции с параметрами обобщенного типа.

public interface IBinaryOperations‹T› {

 T Add(T arg1, T arg2);

 T Subtract(T arg1, T arg2);

 T Multiply(T arg1, T arg2);

 T Divide(T arg1, T arg2);

}

Известно, что интерфейсы остаются почти бесполезными, пока они не реализованы некоторым классом или структурой. При реализации обобщенного интерфейса поддерживающий его тип указывает тип заполнителя.

public class BasicMath: IBinaryOperations‹int› {

 public int Add(int arg1, int arg2) { return arg1 + arg2; }

 public int Subtract(int arg1, int arg2) { return arg1 – arg2; }

 public int Multiply(int arg1, int arg2) { return arg1 * arg2; }

 public int Divide(int arg1, int arg2) { return arg1 / arg2; }

}

После этого вы можете использовать BasicMath, как и ожидали.

static void Main(string[] args) {

 Console.WriteLine("***** Обобщенные интерфейсы *****\n");

 BasicMath m = new BasicMath();

 Console.WriteLine("1 + 1 = {0}", m.Add(1, 1));

 Console.ReadLine();

}

Если вместо этого требуется создать класс BasicMath, действующий на числа с плавающим десятичным разделителем, можно конкретизировать параметр типа так.

public class BasicMath: IBinaryOperations‹double› {

 public double Add(double arg1, double arg2) { return arg1 + arg2; }

 …

}

Исходный код. Проект GenericInterface размещен в подкаталоге, соответствующем главе 10.

<p><strong>Создание обобщенных делегатов</strong></p>

Наконец, что не менее важно, .NET 2.0 позволяет определять обобщенные типы делегата. Предположим, например, что требуется определить делегат, который сможет вызывать любой метод, возвращающий void и принимающий один аргумент. Если аргумент может меняться, это можно учесть с помощью параметра типа. Для примера рассмотрим следующий программный код (обратите внимание на то, что целевые объекты делегата регистрируются как с помощью "традиционного" синтаксиса делегата, так и с помощью группового преобразования метода).

namespace GenericDelegate {

 // Этот обобщенный делегат может вызвать любой метод,

 // возвращающий void и принимающий один параметр.

 public delegate void MyGenericDelegate‹T›(T arg);

 class Program {

  static void Main(string[] args) {

   Console.WriteLine("***** Обобщенные делегаты *****\n");

   // Регистрация цели с помощью 'традиционного'

   // синтаксиса делегата.

   MyGenericDelegate‹string› strTarget = new MyGenericDelegate‹string›(StringTarget);

   strTarget("Некоторые строковые данные");

   // Регистрация цели с помощью

Перейти на страницу:

Похожие книги