Ковариантность делегатов

Ковариантность делегатов

К этому моменту вы должны чувствовать себя более уверенно при создании и использовании типов делегата. Перед тем как перейти к изучению синтаксиса событий в C#, мы рассмотрим новую возможность .NET 2.0, связанную с делегатами и обозначенную термином ковариантность. Вы могли обратить внимание на то, что все делегаты, созданные нами до сих пор, указывали на методы, возвращающие простые числовые типы данных (или не возвращающие значений вообще). Но предположим, что нам нужен делегат, способный указывать на методы, возвращающие пользовательский тип класса.

// Определение делегата, который позволит указывать на объекты,

// возвращающие типы Car.

public delegate Car ObtainCarDelegate();

Мы можем определить целевой объект для делегата так, как обычно.

class Program {

 public delegate Car ObtainCarDelegate();

 public static Car GetBasicCar() {return new Car();}

 static void Main(string[] args) {

  ObtainCarDelegate targetA = new ObtainCarDelegate(GetBasicCar);

  Car c = targetA();

  Console.ReadLine();

 }

}

Пока что все выглядит прекрасно. Но что делать, если мы получим новый класс SportsCar из типа Car и потребуется делегат, который сможет указывать на методы, возвращаемые этим новым типом класса? До появления .NET 2.0 в таком случае вам пришлось бы определить новый делегат.

// Новый делегат, указывающий на целевые объекты,

// возвращающие типы SportsCar.

public delegate SportsCar ObtainSportsCarDelegate();

У нас теперь два типа делегата, и мы должны создать по экземпляру каждого из них, чтобы получить типы Car и SportsCar.

class Program {

 public delegate Car ObtainCarDelegate();

 public delegate SportsCar ObtainSportsCarDelegate();

 public static Car GetBasicCar() {return new Car(); }

 public static SportsCar GetSportsCar() {return new SportsCar();}

 static void Main(string[] args) {

  ObtainCarDelegate targetA = new ObtainCarDelegate(GetBasicCar);

  Car с = targetA();

  ObtainSportsCarDelegate targetB = new ObtainSportsCarDelegate(GetSportsCar);

  SportsCar sc = targetB();

  Console.ReadLine();

 }

}

По законам классического наследования в идеале лучше иметь один тип делегата, который мог бы указывать на методы, возвращающие либо тип Car, либо тип SportsCar (в конце концов, тип SportsCar связан с Car отношением наследования). Ковариантность позволяет реализовать именно такую возможность, т.е. построить один делегат, способный указывать на методы, возвращающие типы класса, связанные классическим отношением наследования.

class Program {

 // Определение делегата, способного возвращать

 // как Car, так и SportsCar.

 public delegate Car ObtainVehicalDelegate();

 public static Car GetBasicCar() {return new Car();}

 public static SportsCar GetSportsCar() { return new SportsCar();}

 static void Main(string[] args) {

  Console.WriteLine("***** Ковариантность делегатов ***** ");

  ObtainVehicalDelegate targetA = new ObtainVehicalDelegate(GetBasicCar);

  Car c = targetA();

  // Такое присваивание возможно вследствие ковариантности.

  ObtainVehicalDelegate targetB = new ObtainVehicalDelegate(GetSportsCar);

  SportsCar sc = (SportsCar)targetB();

  Console.ReadLine();

 }

}

Обратите внимание на то, что тип делегата ObtainVehicalDelegate был определен для того, чтобы указывать на методы, возвращающие строго типизованный Car. Однако в условиях ковариантности мы получаем возможность указывать и на методы, возвращающие производные типы. Чтобы получить производный тип, нужно просто выполнить явное преобразование.

Замечание. Точно так же ковариантность обеспечивает возможность создания делегата, который позволит указать на множество методов, получающих объекты, связанные классическим отношением наследования. Более подробная информация имеется в документации .NET Framework 2.0 SDK.

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

Поделитесь на страничке

Следующая глава >

Похожие главы из других книг

Краткий обзор делегатов .NET

Из книги Язык программирования С# 2005 и платформа .NET 2.0. [3-е издание] автора Троелсен Эндрю

Краткий обзор делегатов .NET Напомним, что тип делегата .NET – это обеспечивающий типовую безопасность объектно-ориентированный указатель функции. Когда вы объявляете делегат .NET, компилятор C# отвечает на это созданием изолированного класса, полученного из System.MulticastDelegate


Асинхронная природа делегатов

Из книги Основы объектно-ориентированного программирования автора Мейер Бертран

Асинхронная природа делегатов Если для вас тема многопоточных приложений является новой, вы можете спросить, чем же на самом деле является асинхронный вызов метода. Вы, без сомнения, знаете о том, что для выполнения некоторых программных операций требуется время.


Ковариантность и скрытие потомком

Из книги QT 4: программирование GUI на С++ автора Бланшет Жасмин

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


Ковариантность

Из книги автора

Ковариантность Что происходит с аргументами компонента при переопределении его типа? Это важнейшая проблема, и мы уже видели ряд примеров ее проявления: устройства и принтеры, одно- и двухсвязные списки и т. д. (см. разделы 16.6, 16.7).Вот еще один пример, помогающий уяснить