Т должен быть контравариантно действительным - PullRequest
34 голосов
/ 18 февраля 2011

Что с этим не так?

interface IRepository<out T> where T : IBusinessEntity
{
    IQueryable<T> GetAll();
    void Save(T t);
    void Delete(T t);
}

Там написано:

Недопустимая дисперсия: параметр типа 'T' должен быть контравариантно действительным для 'MyNamespace.IRepository.Delete (T)'. 'T' является ковариантным.

Ответы [ 3 ]

59 голосов
/ 18 февраля 2011

Подумайте, что произойдет, если компилятор допустит следующее:

interface IR<out T>
{
    void D(T t);
}

class C : IR<Mammal>
{
    public void D(Mammal m)
    {
        m.GrowHair();
    }
}
...
IR<Animal> x = new C(); 
// legal because T is covariant and Mammal is convertible to Animal
x.D(new Fish()); // legal because IR<Animal>.D takes an Animal

И вы только что попытались отрастить волосы на рыбе.

«Out» означает «T используется только в выходных позициях».Вы используете его в позиции ввода.

41 голосов
/ 18 февраля 2011

Параметр типа out можно использовать только ковариантно, т. Е. В типе возвращаемого значения.Следовательно, IQueryable<T> GetAll() является правильным, а void Delete(T t) - нет.

Поскольку T используется одновременно и контравариантно в вашем классе, вы не можете использовать out здесь (или in).

Если вы хотите узнать больше о теоретических основах этого, сделайте небольшой перерыв и прочитайте статью «Ковариация и контравариантность» в Википедии .


Welcomeназад.Итак, что вы делаете, если вам нужны все эти методы в вашем хранилище, но все еще нужен ковариантный интерфейс?Вы можете извлечь ковариантную часть в ее собственный интерфейс:

interface IDataSource<out T> where T : IBusinessEntity
{
    IQueryable<T> GetAll();
}

interface IRepository<T> : IDataSource<T> where T : IBusinessEntity
{
    void Save(T t);
    void Delete(T t);
}

Так же .NET BCL решает эту проблему: IEnumerable<out T> является ковариантным, но поддерживает только «операции чтения».ICollection<T> является подтипом IEnumerable<out T>, допускает операции чтения и записи и, таким образом, не может быть сам ковариантным.

21 голосов
/ 18 февраля 2011

Следующие два метода неверны:

void Save(T t);
void Delete(T t);

В качестве аргумента метода нельзя указывать T.Только в качестве возвращаемого типа, если вы хотите, чтобы он был ковариантным (out T) в вашем универсальном определении.

Или, если вы хотите использовать контравариантность, вы можете использовать универсальный параметр только в качестве аргумента метода, а не возвращаемого типа:

interface IRepository<in T> where T : IBusinessEntity
{
    void Save(T t);
    void Delete(T t);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...