为什么IList<T>实现了IEnumerable<T>和ICollection<T>,而ICollection<T>本身就实现了IEnumerable<T>?

5
为什么IList被定义成这样?
public interface IList<T> : ICollection<T>, IEnumerable<T>, IEnumerable

public interface ICollection<T> : IEnumerable<T>, IEnumerable

public interface IEnumerable<T> : IEnumerable

难道它不可能只是

public interface IList<T> : ICollection<T>

所以,为了测试,我创建了这些接口,只是为了确定是否有效!
public interface IOne
{
    string One();
}

public interface ITwo : IOne
{
    string Two();
}

public interface IThree : ITwo, IOne
{
    string Three();
}

虽然这是完全可以接受的,但Resharper会抱怨“冗余接口”。

微软为什么要采用这种实现方式?有任何想法吗?


1
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Jon Skeet
@JonSkeet:刚刚按下了“F12” /“转到定义”功能键,查看了IList <T> 。它显示了来自程序集元数据方法签名,我从那里就可以看到了。 - now he who must not be named.
1
顺便提一下,只有真正是代码的东西才使用反引号会更有帮助。(我已经从你的帖子中删除了额外的部分) - Jon Skeet
@JonSkeet:谢谢Jon。我会纠正它。 - now he who must not be named.
2
以防你想知道,我已经删除了我的答案,因为我认为它是不正确的 - 我怀疑在编译时代码确实是那样的。我无法推测为什么...我猜可能是接口编写者的个人偏好。 - Jon Skeet
请参考以下来源:IList<T>的基接口列表中不包括IEnumerable<T>IEnumerable。同样,ICollection<T>也不包括IEnumerable - user4003407
1个回答

10

"继承"这个词在软件工程中是最容易引起误解的术语之一。你并没有继承任何东西,因为接口没有任何实现,所以你也不能继承它。你只继承了实现方法的需求。

通过重复接口声明来增加该需求并不会改变任何内容,因为你已经有了这个需求,增加额外的需求也没有任何区别。所以由于这并不重要,Microsoft很贴心地重复了接口,这样你就可以一下子看出List实现了哪些接口。你无需深入接口声明即可看到List实现了IEnumerable。这是一种自我记录的编码风格,值得推荐。

但请注意这个问题的另一面,具有完全相同方法的两个不同接口可以仅使用一个单独的方法实现。虽然这通常非常有用,但有时并不是你想要的。比如ICowboy和IPainter都有一个Draw()方法。它们应该不做相同的事情:) 那么你必须退而求其次,采用显式实现来避免歧义。

针对Resharper的投诉,它当然没有太大帮助。Resharper倾向于从程序员那里假设最糟糕的情况。但如果你想让它闭嘴,那么你需要从IThree的继承列表中删除IOne,因为这是多余的。对于实现IThree的类,同样需要从继承列表中删除ITwo和IOne。或者只需关闭警告。


2
良好的建议 => 推荐自我文档化风格。 - Jenish Rabadiya
1
感谢@Hans。此外,Eric Lippert在这里非常好地解释了这个问题 http://blogs.msdn.com/b/ericlippert/archive/2011/04/04/so-many-interfaces.aspx#comments - now he who must not be named.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接