为什么`IList <T>`不继承自`IReadOnlyList <T>`?

Lou*_*Lou 28 .net c# generics .net-4.5

什么时候IReadOnlyList<T>在.NET 4.5中引入,有一段时间我认为拼图的缺失部分最终被插入到位:一种传递真正的只读索引接口的方法,以前我必须使用我自己的只读接口并创建包装器围绕一切的课程.

我期待接口被放置在"自然"层次结构中,理想情况是:

IEnumerable<T> 
.GetEnumerator()
      -> IReadOnlyCollection<T> : IEnumerable<T>
      .Count
            -> IReadOnlyList<T> : IReadOnlyCollection<T>
            .Item[...]
                     -> IList<T> : IReadOnlyList<T>
                     .Add(...)
                     .Clear()
                     .Contains(...)
                     (etc)
Run Code Online (Sandbox Code Playgroud)

但是,事实证明,IList<T>不会继承IReadOnlyList<T>.

是否有一个原因?

小智 32

@wb 在包含答案的注释中放置了新接口IReadOnlyList和IReadOnlyDictionary的链接:

为什么我们不改变现有接口来扩展只读接口?

它看起来是一个合理的假设,因为只读接口纯粹是读写接口的一个子集.不幸的是,它是不兼容的,因为在元数据级别,每个接口上的每个方法都有自己的插槽(这使得显式接口实现工作).


Immo Landwerth | .NET Framework团队(BCL)| http://blogs.msdn.com/b/bclteam/

为了更清楚地解释这一点:

假设为.NET 4.0编写的程序包含一个MyList<T>实现的类IList<T>.它显然无法实现,IReadOnlyList<T>因为该接口不存在.

现在假设系统管理员安装了.NET 4.5并假设.NET 4.5已经IList<T>实现了IReadOnlyList<T>.

如果然后加载程序,运行时将检测到MyList<T>要实现的声明IList<T>,但实际上并没有实现所有方法:它没有实现IReadOnlyList<T>的方法.该计划将不再有效.

C#编译器可能能够按名称匹配方法,但运行时不会这样做.由于.NET 4.5应该具有向后二进制兼容性,因此无法扩展接口以实现其他接口,即使这些其他接口包含所需方法的严格子集也是如此.

  • +1另一个基于引用对显式实现的引用的示例.如果一个类已经有一个显式的`int IList <T> .Count ...`实现和`IList <T>`将继承自`IReadOnlyList <T>`,那么Count将属于后者并且现有的实现将失败,即使用正确的框架构建. (4认同)
  • .net-5.x 是否愿意打破 ABI 并解决这个问题? (2认同)
  • @binki 据我所知,.NET 5 已经更名为 .NET Core(但如果我错了,有人可以纠正我,这实际上是别的东西)。在 .NET Core 中,[`IList&lt;T&gt;`](https://github.com/dotnet/coreclr/blob/master/src/mscorlib/src/System/Collections/Generic/IList.cs) 仍然没有当前实现`IReadOnlyList&lt;T&gt;`。 (2认同)
  • @hvd:我认为.NET Core的目标之一是在合理的范围内保持API兼容性,以便尽可能容易地将** code **(如果不是二进制文件)迁移到整个框架,或者从整个框架迁移。我不确定... (2认同)