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

C# 为什么核心类型只部分实现接口?,c#,.net,collections,interface,C#,.net,Collections,Interface,Q1为什么.NET中的新类只部分实现接口 Q2我的代码是否也要这样做 我问了这个问题,所以我想,好吧,那是很久以前的事了,你可以有不同的用法等等,现在这种实现只支持一致性的原因。但新课程也能做到这一点 旧的 int[] list = new int[] {}; IList iList = (IList)list; ilist.Add(1); //exception here 新的 ICollection c = new ConcurrentQueue<int>(); var roo

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
ICollection c=new ConcurrentQueue();
var root=c.SyncRoot//这里例外
更新


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

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

IList的文档说明:

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

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

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


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

您可能会认为,原始设计中的接口不够精细。例如,大多数人从不使用
SyncRoot
——它可能位于不同的界面上。同样,不幸的是,例如,没有接口提供只读索引器访问

就目前情况而言,接口就是这样。尽管如此,实现主
IList[]
/
ICollection[]
/
IEnumerable[]
接口仍然非常方便-它为大多数调用者提供了访问所需内容的权限。。。因此,在第一个示例中使用索引器,在第二个示例中使用
Add


公平地说,他们也提供了
IsFixedSize
IsReadOnly
——查询第一个会导致您不调用
Add
。Re
SyncRoot
——这在
ConcurrentQueue
中可能没有意义,任何实现都会破坏该类型的逻辑。通常我会说“那么它不是那种类型;不要实现接口”,但重复我前面的语句大多数人从不使用
SyncRoot
——所以我同意;p

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

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

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


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

但这有点破坏了界面背后的理念。它应该为实现接口的任何类型定义一组通用的操作,您可以依赖这些操作来实现接口,这样您就可以在接口的不同实现之间切换,它们都将,