为啥 C# 中的集合类(如 ArrayList)继承自多个接口,如果其中一个接口继承自其余接口?

Posted

技术标签:

【中文标题】为啥 C# 中的集合类(如 ArrayList)继承自多个接口,如果其中一个接口继承自其余接口?【英文标题】:Why collections classes in C# (like ArrayList) inherit from multiple interfaces if one of these interfaces inherits from the remaining?为什么 C# 中的集合类(如 ArrayList)继承自多个接口,如果其中一个接口继承自其余接口? 【发布时间】:2010-11-04 15:13:40 【问题描述】:

当我在ArrayList关键字上按f12进入vs2008生成的元数据时,发现生成的类声明如下

public class ArrayList : IList, ICollection, IEnumerable, ICloneable

我知道 IList 已经继承自 ICollection 和 IEnumerable,那么为什么 ArrayList 会冗余继承自这些接口呢?

【问题讨论】:

+1 这是一个很好的问题。 我同意。在反射器中 ArrayList 被定义为公共类 ArrayList : IList, ICollection, IEnumerable, ICloneable 我做了一些研究并用代码示例添加了答案 为什么重要?把上面提到的每一个接口都包含进去,是不是让事情变得更清楚了? @mP- 这并不重要,但这仍然是一个有趣的问题! 【参考方案1】:

我的猜测是 CLR 不支持从另一个接口继承的接口。

然而,C# 确实支持这种结构,但必须“扁平化”继承树以符合 CLR。​​

[编辑]

在听取下面的建议后,快速设置一个 VB.Net 项目:

Public Interface IOne
    Sub DoIt()
End Interface

Public Interface ITwo
    Inherits IOne
    Sub DoIt2()
End Interface

Public Class Class1
    Implements ITwo

    Public Sub DoIt() Implements IOne.DoIt
        Throw New NotImplementedException()
    End Sub

    Public Sub DoIt2() Implements ITwo.DoIt2
        Throw New NotImplementedException()
    End Sub
End Class

编译结果如下(C#):

public class Class1 : ITwo

    public Class1();
    public void DoIt();
    public void DoIt2();

这表明 VB.Net 确实扁平化接口层次结构,而不是 C#。我不知道为什么会这样。

【讨论】:

-1:与其在三周后猜测,不如在 VB.NET 中尝试并找出答案,然后再回答。当然不用着急。【参考方案2】:

好的,我已经做了一些研究。如果您创建以下层次结构:

  public interface One
    
        void DoIt();
    

    public interface Two : One
    
        void DoItMore();
    

    public class Magic : Two
     
        public void DoItMore()
        
            throw new NotImplementedException();
        

        public void DoIt()
        
            throw new NotImplementedException();
        
    

并编译它,然后在不同的解决方案中引用 DLL,键入 Magic 并按 F12,您将得到以下信息:

 public class Magic : Two, One
    
        public Magic();

        public void DoIt();
        public void DoItMore();
    

您会看到接口层次结构是扁平化的,还是编译器正在添加接口?如果你使用反射器,你也会得到相同的结果。

更新:如果你在 ILDASM 中打开 DLL,你会看到它说:

实现...两个

实现...一个。

【讨论】:

我猜是因为知道这一点非常方便。不是每个人都知道 IList 继承自 ICollection 和 IEnumerable(或者用另一个层次结构替换这个句子)。【参考方案3】:

不要接受这个作为答案。

我在重复上面 workmad3 所说的话。

通过在 ArrayList 中实现它,人们很容易知道 ArrayList 实现了哪些接口,而不是通过 IList 发现它实现了 ICollection 和 IEnumerable。

这避免了来回继承链的需要。

编辑:在基本级别,实现另一个接口的接口不能提供实现。派生的类(来自 IList)因此也间接实现了 ICollection 和 IEnumerable。因此,即使您编写自己的实现 IList 的类(而不是在声明中添加 ICollection、IEnumerable) - 您也会看到它必须提供 ICollection 和 IEnumerable 的实现。

workmad3 的推理是有道理的。

【讨论】:

【参考方案4】:

来自MSDN....

如果一个类实现了两个接口 包含具有相同的成员 签名,然后实现 班上的成员会导致 使用该成员作为他们的接口 执行。

还使用了显式实现 解决两个接口的情况 每个声明不同的成员 相同的名称,例如属性和 方法:

【讨论】:

我的问题是,为什么 ArrayList 继承自 ICollection 和 IEnumerable 只要 IList 继承自两者???【参考方案5】:

我只是猜测,但我认为实际上它仅在代码中实现 IList,但文档还显示了其余接口,以便使用该类的程序员明确说明。

【讨论】:

即使它确实明确地实现了所有这些,接口的明确性也很好,因为您可以通过查看这些接口来告诉您需要实现的所有内容,而不是挖掘接口及其基础等. 我明白你的意思,但我怀疑这是否是一件好事。我想有点多余不会有什么坏处,但是我从来没有看到自己以这种方式编写代码,这仍然引出了一个问题:MS 在哪里记录了他们这样做的意图?【参考方案6】:

显示额外的接口是因为它们被 IList 隐含。如果实现 IList,则还必须实现 ICollection 和 IEnumerable。

【讨论】:

好吧,也就是说它是从vs生成的,不是ArrayList的真正声明? 是的。如果您使用 Reflector 查看基本类型,您会看到它仅显式实现了 IList 和 ICloneable。微软公开的Rotor源代码也是如此:123aspx.com/Rotor/RotorSrc.aspx?rot=39810 我猜 VS 可能会扁平化方法实现。也就是说,既然IList实现了ICollection,ArrayList就是提供了ICollection方法的实现。 但它已经在文档中msdn.microsoft.com/en-us/library/…

以上是关于为啥 C# 中的集合类(如 ArrayList)继承自多个接口,如果其中一个接口继承自其余接口?的主要内容,如果未能解决你的问题,请参考以下文章

C#语言基础——集合(ArrayList集合)

C#中集合的使用--ArrayList

java 中关于继集合类的整理

集合 ArrayList 类

C#中的Collections命名空间

C# 集合(ArrayList)的方法和使用