Этот вопрос довольно запутанный.Дайте мне посмотреть, смогу ли я уточнить это.
Когда я пытаюсь реализовать IGreatInterface
, компилятор помечает ошибку для aMethodBeta()
, потому что я сделал этот метод, используя подтип IAnInterface
Iхочу реализовать этот метод следующим образом: Object aMethodBeta(AnInterestingClass parameter)
.
Это не законно.Упрощенно несколько:
class Food {}
class Fruit : Food {}
class Meat : Food {}
interface IEater
{
void Eat(Food food);
}
class Vegetarian : IEater
{
public void Eat(Fruit fruit);
}
Класс Vegetarian
не выполняет контракт IEater
.Вы должны быть в состоянии передать любую пищу для еды, но Vegetarian
принимает только фрукты.C # не поддерживает формальный параметр ковариации виртуального метода , потому что это небезопасно.
Теперь вы можете сказать, как насчет этого:
interface IFruitEater
{
void Eat(Fruit fruit);
}
class Omnivore : IFruitEater
{
public void Eat(Food food);
}
Теперь мы имеемприобретенный тип безопасности;Omnivore
можно использовать в качестве IFruitEater
, поскольку Omnivore
может есть фрукты, а также любую другую пищу.
К сожалению, C # не поддерживает виртуальный метод формального параметра с контрастом типа хотя в теории это безопасно.Немногие языки поддерживают это.
Точно так же C # не поддерживает дисперсию типа возвращаемого виртуального метода .
Я не уверен, действительно ли это ответило на ваш вопрос или нет,Можете ли вы уточнить вопрос?
ОБНОВЛЕНИЕ:
Как насчет:
interface IEater
{
void Eat<T>(T t) where T : Food;
}
class Vegetarian : IEater
{
// I only want to eat fruit!
public void Eat<Fruit>(Fruit food) { }
}
Нет, это тоже не законно.Контракт IEater
заключается в том, что вы предоставите метод Eat<T>
, который может принимать любой T
, то есть Food
.Вы не можете частично выполнить договор, больше, чем вы могли бы сделать это:
interface IAdder
{
int Add(int x, int y);
}
class Adder : IAdder
{
// I only know how to add two!
public int Add(2, int y){ ... }
}
Однако вы можете сделать это:
interface IEater<T> where T : Food
{
void Eat(T t);
}
class Vegetarian : IEater<Fruit>
{
public void Eat(Fruit fruit) { }
}
Это совершенно законно,Тем не менее, вы не можете сделать:
interface IEater<T> where T : Food
{
void Eat(T t);
}
class Omnivore : IEater<Fruit>
{
public void Eat(Food food) { }
}
Потому что, опять же, C # не поддерживает виртуальный метод формального параметра контравариантности или ковариации.
Обратите внимание, что C # поддерживает поддержку параметрического полиморфизма ковариации , когда известно, что это безопасно для типов.Например, это законно:
IEnumerable<Fruit> fruit = whatever;
IEnumerable<Food> food = fruit;
Последовательность фруктов может использоваться как последовательность пищи.Или,
IComparable<Fruit> fruitComparer = whatever;
IComparable<Apples> appleComparer = fruitComparer;
Если у вас есть что-то, что может сравнивать любые два фрукта, тогда оно может сравнивать любые два яблока.
Однако такой вид ковариации и контравариантности допустим только тогда, когда всеверно следующее: (1) дисперсия доказуемо безопасна для типов, (2) автор аннотации добавлен тип, указывающий желаемые совместные и противоположные дисперсии, (3) все аргументы переменного типа являются ссылочными типами, (4)универсальный тип является делегатом или интерфейсом.