Ковариация/контравариантность: как сделать следующий код
UPDATE: Следующий код имеет смысл только в С# 4.0 (Visual Studio 2010)
Кажется, что у меня есть некоторое непонимание ковариации/контравариантности. Может ли кто-нибудь сказать мне, почему следующий код не компилируется?
public class TestOne<TBase>
{
public IEnumerable<TBase> Method<TDerived>(IEnumerable<TDerived> values)
where TDerived: TBase
{
return values;
}
}
пока этот компилируется: (!!!)
public interface IBase
{
}
public interface IDerived: IBase
{
}
public class TestTwo
{
public IEnumerable<IBase> Method(IEnumerable<IDerived> values)
{
return values;
}
}
Ответы
Ответ 1
Ковариация применяется только к ссылочным типам (для аргументов типа), поэтому вам нужно добавить ограничение класса:
public IEnumerable<TBase> Method<TDerived>(IEnumerable<TDerived> values)
where TDerived : class, TBase
{
return values;
}
Это предотвратит попытку конвертировать, скажем, IEnumerable<int>
в IEnumerable<object>
, что является недопустимым.
Ответ 2
Я не могу думать о ситуации, в которой вам действительно нужно TDerived
. Использовать TBase
достаточно:
public class TestOne<TBase>
{
public IEnumerable<TBase> Method(IEnumerable<TBase> values)
{
return values;
}
}
В конце концов, у вас нет информации о TDerived
, кроме того, что это TBase
...
Ответ 3
Ни один из них не скомпилирован для меня. Оба отказались от неявного перевода из Super (T/I) в Base (T/I). Однако, когда я добавил явный случай, оба скомпилированы.
public IEnumerable<TBase> Method<TSuper>(IEnumerable<TSuper> values)
where TSuper: TBase
{
return (IEnumerable<TBase>) values;
}