Проблема в том, что дисперсия работает только со ссылочными типами или преобразованиями идентификаторов из спецификации (раздел 13.1.3.2):
A type T<A1, …, An> is variance-convertible to a type T<B1, …, Bn> if T is either an interface or a delegate type declared with the variant type parameters T<X1, …, Xn>, and for each variant type parameter Xi one of the following holds:
• Xi is covariant and an implicit reference or identity conversion exists from Ai to Bi
• Xi is contravariant and an implicit reference or identity conversion exists from Bi to Ai
• Xi is invariant and an identity conversion exists from Ai to Bi
Компилятор не может проверить, что TFoo
не являетсяструктура, которая реализует IFoo<IChild>
, поэтому она не находит нужный метод расширения.Добавление ограничения class
к DoSomething
также не решает проблему, поскольку типы значений по-прежнему наследуются от object
, поэтому удовлетворяют ограничению.IFoo<IChild> bar = foo;
и DoSomethingElse(foo);
оба работают, потому что у каждого есть неявное приведение от foo
до IFoo<IChild>
, что является ссылочным типом.
Я бы задал тот же вопрос, который Майк Штробель задал в комментариях выше: почему бы не изменить свою подпись DoSomething с
public static void DoSomething<TFoo>(this TFoo foo)
where TFoo : IFoo<IChild>
на
public static void DoSomething<TFoo>(this IFoo<IChild> foo)
Похоже, вы ничего не получите, сделав метод универсальным.
Несколькопосты, которые я прочитал по теме:
Общий метод расширения: аргумент типа не может быть выведен из использования
Эрик Липперт - Ограничения не являются частьюподпись
C # типовое ограничение типа