Подтвердить что ты не робот

Ковариация/контравариантность: как сделать следующий код

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;
    }
}
4b9b3361

Ответ 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;
    }