为什么核心类型只部分实现接口

本文关键字:实现 接口 核心 类型 为什么 | 更新日期: 2023-09-27 17:57:10

Q1 为什么 .NET 中的新类只部分实现接口?

Q2 我应该在我的代码中做同样的事情吗?

我在这里问了这个问题,所以我想,好吧,那是很久以前的事了,你可以有不同的用法等,现在支持这样的实现只是出于一致性的原因。但新类也可以做到这一点。

int[] list = new int[] {};
IList iList = (IList)list;
ilist.Add(1); //exception here

新增功能

ICollection c = new ConcurrentQueue<int>();
var root = c.SyncRoot; //exception here

更新

并不担心为什么我会收到例外,很明显。但我不明白为什么实现定义良好的合约,而不是所有成员(这可能导致令人不快的运行时异常)?

为什么核心类型只部分实现接口

你可能会争辩说,在原始设计中,接口不够精细。例如,大多数人从不使用SyncRoot - 它可能在不同的界面上。同样,不幸的是,例如,没有接口提供只读索引器访问。

就目前而言,接口就是它们。不过,实现主要的IList[<T>]/ICollection[<T>]/IEnumerable[<T>]接口仍然非常方便 - 它为大多数调用者提供了对他们需要的内容的访问......因此,索引在第一个示例中,Add在第二个示例中。

公平地说,他们确实还提供IsFixedSizeIsReadOnly - 查询第一个会导致您不打电话给Add。重新SyncRoot - 这大概在ConcurrentQueue<T>中没有意义,任何实现都会破坏类型的逻辑。通常我会说"那么它不是那种类型;不要实现接口",但要重复我之前的说法...... 大多数人从不使用SyncRoot - 所以我可以接受它;p

一个小问题,所有接口都必须完全实现。 接口的所有方法和属性必须由任何实现器实现,否则由编译器实现。您指的是调用接口的某些方法时可能引发的运行时错误。

IList的文档指出:

IList 是 ICollection 接口的后代,是所有非泛型列表的基本接口。IList 实现分为三类:只读、固定大小和可变大小。只读 IList 无法修改。固定大小的 IList 不允许添加或删除元素,但它允许修改现有元素。可变大小的 IList 允许添加、删除和修改元素。

当您调用特定实现无法满足的方法时,您会收到异常。

为什么界面是这样设计的? 人们只能推测,但这种特殊的设计允许IsFixedSizeIsReadOnly等属性在接口实例的生命周期内发生变化。

你应该这样设计你的界面吗? 这取决于这样的设计是否可取并满足您的需求。

从OOP的角度来看,这是完全错误的。他们应该要么制作更小的接口,要么不把它们放在像数组这样的东西上。然而,.NET Framework的设计者并不愚蠢,他们可能做了一些权衡。例如,需要IEnumerable来实现IDisposable,从OOP设计的角度来看,这没有意义,但对于数据库读取器有一些性能优势。因此,可能被黑客入侵到类中的实现(如您的示例)有一些好处,但从 OOP 的角度来看,它们是错误的,除非您知道您正在用好的设计来交易什么,否则您不应该这样做。

我怀疑部分实现接口的存在是设计决策的结果,不允许类或接口具有同名的独立可读属性和可写属性,并自动适当地使用它们(例如,如果一个类具有可读属性"foo"和可写属性"foo",请使用可读属性进行读取,使用可写属性进行写入)。 这种设计决策使得拆分某些接口的读取和写入方面变得很尴尬。

理想情况下,不是只有一个接口 IList,而是有通用的逆变接口 IReadableByIndex、通用协变接口 IWriteableByIndex、IAppendable、IGrowableByIndex(包括各种插入和删除函数)和非通用的 IMovableByIndex(基于索引的复制、交换和滚动函数),也许还有 IComparableByIndex(给定两个索引,比较项目)。 接口 IList 可以实现所有这些,但也有许多有用的子集(其中许多可能是逆变或协变)。 请注意,一些非泛型例程的存在将允许在任何实现 IComparableByIndex 和 IMovableByIndex 的集合上实现排序之类的东西,而不必担心集合的确切类型。

不幸的是,要使IList的拆分真正有用,有必要将IReadableByIndex和IWritableByIndex作为单独的接口。 这反过来又会在尝试编写将继承两个接口的代码时带来困难,因为编译器在尝试使用索引访问器时会抱怨歧义。 由于IReadableByIndex和IWritableByIndex最终不得不合并,Microsoft可能认为它也可以将所有内容归入IList。