Непрерывная реализация дисперсии реализации интерфейса должна быть ковариантной в типе возврата и контравариантной в типах аргументов .
Например:
public interface IFoo
{
object Flurp(Array array);
}
public class GoodFoo : IFoo
{
public int Flurp(Array array) { ... }
}
public class NiceFoo : IFoo
{
public object Flurp(IEnumerable enumerable) { ... }
}
Оба законны по "новым" правилам, верно? Но что по этому поводу:
public class QuestionableFoo : IFoo
{
public double Flurp(Array array) { ... }
public object Flurp(IEnumerable enumerable) { ... }
}
Трудно сказать, какая неявная реализация лучше здесь. Первый - точное соответствие для типа аргумента, но не тип возвращаемого значения. Второе - точное совпадение для возвращаемого типа, но не типа аргумента. Я склоняюсь к первому, потому что тот, кто использует интерфейс IFoo
, может только дать ему Array
, но это все еще не совсем ясно.
И это далеко не худшее, безусловно. Что если мы сделаем это вместо этого:
public class EvilFoo : IFoo
{
public object Flurp(ICollection collection) { ... }
public object Flurp(ICloneable cloneable) { ... }
}
Кто из них выиграет приз? Это вполне допустимая перегрузка, но ICollection
и ICloneable
не имеют никакого отношения друг к другу, а Array
реализует их обоих. Я не вижу здесь очевидного решения.
Это только ухудшится, если мы начнем добавлять перегрузки к самому интерфейсу:
public interface ISuck
{
Stream Munge(ArrayList list);
Stream Munge(Hashtable ht);
string Munge(NameValueCollection nvc);
object Munge(IEnumerable enumerable);
}
public class HateHateHate : ISuck
{
public FileStream Munge(ICollection collection);
public NetworkStream Munge(IEnumerable enumerable);
public MemoryStream Munge(Hashtable ht);
public Stream Munge(ICloneable cloneable);
public object Munge(object o);
public Stream Munge(IDictionary dic);
}
Удачи, пытаясь разгадать эту тайну, не сходя с ума.
Конечно, все это спорный вопрос, если вы утверждаете, что реализации интерфейса должны поддерживать только возврат типа дисперсии и не аргумент типа дисперсии. Но почти все считают такую половинную реализацию полностью сломанной и начинают рассылать спам-сообщения об ошибках, поэтому я не думаю, что команда C # собирается это сделать.
Я не знаю, является ли это официальной причиной того, почему она не поддерживается в C # сегодня, но она должна служить хорошим примером того типа кода «только для записи», к которому он может привести, и частью Философия дизайна команды C # состоит в том, чтобы попытаться помешать разработчикам писать ужасный код.