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

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

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

   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);

}

<p>Имитация обобщенных делегатов в .NET 1.1</p>

Как видите, обобщенные делегаты предлагают более гибкий подход для указания вызываемых методов. В рамках .NET 1.1 аналогичного результата можно достичь с помощью базового System.Object.

public delegate void MyDelegate(object arg);

Это позволяет посылать любой тип данных целевому объекту делегата, но при этом не гарантируется типовая безопасность, а кроме того, остаются нерешенными проблемы создания объектных образов. Предположим, например, что мы создали два экземпляра MyDelegate, которые указывают на один и тот же метод MyTarget. Обратите внимание на проблемы создания объектных образов и восстановления значений, а также на отсутствие гарантий типовой безопасности.

class Program {

 static void Main(string[] args) {

  …

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

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

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