接口实现方差的完整实现必须在返回类型中是协变的,在参数类型中是逆变的。
例如:
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# 团队设计的一部分哲学是试图阻止开发人员编写糟糕的代码。