Co - и ошибки Контравариантности в.NET 4.0

Некоторое странное поведение с C# 4.0 co-и поддержкой контравариантности:

using System;

class Program {
  static void Foo(object x) { }
  static void Main() {
    Action<string> action = _ => { };

    // C# 3.5 supports static co- and contravariant method groups
    // conversions to delegates types, so this is perfectly legal:
    action += Foo;

    // since C# 4.0 much better supports co- and contravariance
    // for interfaces and delegates, this is should be legal too:
    action += new Action<object>(Foo);
  }
}

Это - результаты с ArgumentException: Delegates must be of the same type.

Странный, не так ли? Почему Delegate.Combine() (который явлен назван при выполнении += операция на делегатах), не поддерживает co - и контравариантность во времени выполнения?

Кроме того, я нашел что BCL's System.EventHandler<TEventArgs> тип делегата не делает имеет контравариантную аннотацию на, он универсален TEventArgs параметр! Почему? Это совершенно законно, TEventArgs введите используемый только во входном положении. Возможно, нет никакой контравариантной аннотации из-за этого, приятно скрывает ошибку с Delegate.Combine()? ;)

p.s. Все это влияет на VS2010 RC и более поздние версии.

35
задан controlflow 22 February 2010 в 09:09
поделиться

2 ответа

Короче говоря: объединение делегатов все испортило в отношении дисперсии. Мы обнаружили это в конце цикла. Мы работаем с командой CLR, чтобы посмотреть, сможем ли мы придумать способ заставить все общие сценарии работать без нарушения обратной совместимости и так далее, но все, что мы придумаем, вероятно, не войдет в выпуск 4.0. Надеюсь, мы все исправим в каком-нибудь пакете обновления. Я прошу прощения за доставленные неудобства.

38
ответ дан 27 November 2019 в 07:19
поделиться

Ковариация и контравариантность определяют отношение наследования между универсальными типами. Когда у вас есть ковариация и контравариантность, классы G и G могут находиться в некоторых отношениях наследования в зависимости от того, что A и B есть. Вы можете извлечь из этого пользу при вызове универсальных методов.

Однако метод Delegate.Combine не является универсальным, и в документации четко указано , когда будет выдано исключение:

ArgumentException - Оба a и b не являются нулевой ссылкой ( Ничего в Visual Basic), а a и b не являются экземплярами одного и того же типа делегата.

Итак, Action и Action , безусловно, являются экземплярами другого типа делегата (даже если связаны отношениями наследования), поэтому, согласно документации, это вызовет исключение.Звучит разумно, что метод Delegate.Combine может поддерживать этот сценарий, но это всего лишь возможное предложение (очевидно, что до сих пор в этом не было необходимости, потому что вы не можете объявлять унаследованные делегаты, поэтому перед совместным / контр-отклонением , у делегатов нет отношений наследования).

6
ответ дан 27 November 2019 в 07:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: