Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Троелсен Э. Язык программирования С# 2010 и п...docx
Скачиваний:
113
Добавлен:
21.09.2019
Размер:
6.92 Mб
Скачать

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

Вы уже видели при рассмотрении пространства имен 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);

 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.

Создание обобщенных делегатов

Наконец, что не менее важно, .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("Некоторые строковые данные");

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

   // группового преобразования метода.

   MyGenericDelegate‹int› intTarget = IntTarget;

   intTarget(9);

   Console.ReadLine();

  }

  static void StringTarget(string arg) {

   Console.WriteLine("arg в верхнем регистре: {0}", arg.ToUpper());

  }

  static void IntTarget(int arg) {

   Console.WriteLine("++arg: {0}", ++arg);

  }

 }

}

Обратите внимание на то. что MyGenericDelegate‹T› определяет один пара-метр типа, представляющий аргумент, отправляемый целевому объекту делегата. При создании экземпляра этого типа требуется конкретизировать значение параметра типа, а также имя метода, вызываемого делегатом. Так, если вы укажете строковый тип, то отправите целевому методу строковое значение.

// Создание экземпляра MyGenericDelegate‹T›

// со значением string для параметра типа.

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

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

С учетом формата объекта strTarget метод StringTarget() должен теперь получить в качестве параметра одну строку.

static void StringTarget(string arg) {

 Console.WriteLine("arg в верхнем регистре: {0}", arg.ToUpper());

}