Ненарушенная реализация вариативности реализации интерфейса должна быть ковариантной по возвращаемому типу и контравариантной по типам аргументов.
Например:
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#. философия состоит в том, чтобы не дать разработчикам писать ужасный код.
person
Aaronaught
schedule
23.03.2010