问题描述
当 IReadOnlyList<T>
在 .NET 4.5 中被引入时,有那么一刻,我认为这个难题的缺失部分终于被插入到位:一种传递真正的只读可索引接口的方法,以前我将不得不使用我自己的只读接口并围绕所有内容创建包装类.
When IReadOnlyList<T>
was introduced in .NET 4.5, for a moment I thought the missing part of the puzzle was finally inserted in place: a way to pass a true readonly indexable interface where previously I would have to use my own read-only interfaces and create wrapper classes around everything.
我期待将界面放置在自然"内部层次结构,理想情况下是:
I was expecting the interface to be placed inside the "natural" hierarchy, which would ideally be:
IEnumerable<T>
.GetEnumerator()
-> IReadOnlyCollection<T> : IEnumerable<T>
.Count
-> IReadOnlyList<T> : IReadOnlyCollection<T>
.Item[...]
-> IList<T> : IReadOnlyList<T>
.Add(...)
.Clear()
.Contains(...)
(etc)
但是,事实证明,IList
并没有从 IReadOnlyList
继承.
But, as it turns out, IList<T>
doesn't inherit from IReadOnlyList<T>
.
这有什么原因吗?
一些说明:
请注意,IReadOnlyList
只是一个契约,它指出列表提供了一种获取列表计数并读取特定索引处的值的方法.它的名字很糟糕,因为它没有强制要求实际的实现是只读的.
Note that IReadOnlyList<T>
is merely a contract which states that the list provides a way to get the list count and read the value at a certain index. It's poorly-named, because it doesn't enforce that the actual implementation is readonly.
一个List
实现了IEnumerable
,一个IList
继承自IEnumerable
,但这并不意味着这些类只能被枚举.
A List<T>
implements IEnumerable<T>
, an IList<T>
inherits from IEnumerable<T>
, but this doesn't mean that these classes can only be enumerated.
所以,如果你想将一个列表传递给一个方法,并且只允许它被索引(读取),而不是被修改,你需要将它包装在一个新的实例中.同时,您可以将其传递给接受 IEnumerable
或 IList
而无需包装它的方法.这就是我发现的坏处.
So, if you want to pass a list to a method, and only allow it to be indexed (read), but not modified, you need to wrap it in a new instance. At the same time, you can pass it to a method which accepts IEnumerable<T>
or IList<T>
without having to wrap it. This is what I find to be broken.
我也认为正确的名称应该类似于 IReadOnlyCollection
的 ICountable
和 IReadOnlyList
的 IIndexable
:
I also believe the proper name should had been something like ICountable
for IReadOnlyCollection
and IIndexable
for the IReadOnlyList
:
IEnumerable<T>
.GetEnumerator()
-> ICountable<T> : IEnumerable<T>
.Count
-> IIndexable<T> : ICountable<T>
.Item[...]
-> IList<T> : IIndexable<T>
.Add(...)
.Clear()
.Contains(...)
(etc)
推荐答案
@wb 放一个链接到 新接口 IReadOnlyList 和 IReadOnlyDictionary 在包含答案的评论中:
@w.b put a link to New interfaces IReadOnlyList and IReadOnlyDictionary in the comments that contains an answer:
为什么我们不改变现有的接口来扩展只读接口?
它的工作原理看起来是一个合理的假设,因为只读接口纯粹是读写接口的一个子集.不幸的是,它是不兼容的,因为在元数据级别,每个接口上的每个方法都有自己的插槽(这使得显式接口实现工作).
It looks like a reasonable assumption that it works because the read-only interfaces are purely a subset of the read-write interfaces. Unfortunately, it is incompatible because at the metadata level every method on every interface has its own slot (which makes explicit interface implementations work).
伊莫·兰德沃斯 |.NET 框架团队 (BCL) |http://blogs.msdn.com/b/bclteam/
Immo Landwerth | .NET Framework Team (BCL) | http://blogs.msdn.com/b/bclteam/
为了更清楚地解释这一点:
To explain this a bit more clearly:
假设为 .NET 4.0 编写的程序包含一个实现 IList
的类 MyList
.它显然无法实现 IReadOnlyList
,因为该接口不存在.
Suppose that a program written for .NET 4.0 contains a class MyList<T>
that implements IList<T>
. It clearly cannot implement IReadOnlyList<T>
as that interface doesn't exist.
现在假设系统管理员安装了 .NET 4.5 并假设 .NET 4.5 使 IList
实现 IReadOnlyList
.
Now suppose the system administrator installs .NET 4.5 and suppose that .NET 4.5 made IList<T>
implement IReadOnlyList<T>
.
如果随后加载程序,运行时将检测到 MyList
声称实现了 IList
,但实际上并未实现所有方法:它没有实现 IReadOnlyList
的方法.该程序将不再有效.
If the program would then be loaded, the runtime would detect that MyList<T>
claims to implement IList<T>
, but doesn't actually implement all the methods: it doesn't implement IReadOnlyList<T>
's methods. The program would no longer work.
C# 编译器可能能够按名称匹配方法,但运行时不会这样做.由于 .NET 4.5 应该具有向后二进制兼容性,因此无法扩展接口以实现其他接口,即使这些其他接口包含所需方法的严格子集也是如此.
The C# compiler might be able to match the methods by name, but the runtime doesn't do this. Since .NET 4.5 was supposed to have backwards binary compatibility, interfaces couldn't be extended to implement other interfaces, not even if those other interfaces contain a strict subset of the required methods.
这篇关于为什么`IList<T>`不继承自`IReadOnlyList<T>`?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!