IList接口需要Add方法。数组实现此函数,但它只是抛出一个NotImplementedException。这对我来说似乎是非常糟糕的设计。
设计师在做这件事时有什么想法?
答案 0 :(得分:7)
IList可以是只读的 - 如果有疑问,调用者可以在尝试添加或删除元素之前测试IsFixedSize属性,或者在尝试修改元素之前测试IsReadOnly属性。
数组是固定大小的IList。
能够将数组视为列表是很方便的。一个例子是模拟一个返回IList的数据访问方法 - 它可以被模拟为简单地将一个数组转换为IList。
答案 1 :(得分:0)
因为不同对象通常具有不同的能力,所以某些接口包括将由某些但不是所有实现实现的成员。如果假设接口IVehicle
的某些(但不是全部)实现能够附加预告片,则典型的模式是将AttachTrailer
的功能定义为“尝试附加预告片,如果{ {1}}为真,否则抛出CanAttachTrailer
“。 NotSupportedException
的所有实现都能够符合上述规范,无论它们是否可以处理预告片。
IVehicle
可以接收包含Foo
不需要的功能的对象,将该对象传递给方法Foo
,确实需要这些功能,而不需要在任何地方进行任何类型转换,并且Bar
不知道Foo
需要哪些功能。另一个优点是,这使得编写不需要某些功能的代码变得容易,但是当它们存在时可以利用它们。
然而,这种方法存在一些缺点。接口尚无法为任何属性或方法指定默认实现。因此,即使Bar
无法附加预告片的实现也需要包含将IVehicle
返回false
属性的代码,并在其CanAttachTrailer
方法中抛出异常。此外,由于接口不要求实现其许多方法,因此编译器无法知道在尝试调用需要具有无法提供类型的对象的功能的函数时拒绝。
在设计AttachTrailer
时,微软显然认为“可选功能接口”方法的优势超过了缺点。实际上,如果.net为实现接口的类提供了一种方法来推迟他们不希望提供的成员的默认实现,那么就没有理由不在基层接口中包含许多可选功能。为了允许编译时强制执行必要的功能,可以从包含所有所需成员的基础派生出许多接口,并指定实现后者接口的类必须以实际有用的方式实现某些成员。例如,Microsoft可能已定义IList<T>
继承IResizableList<T>
而不添加任何成员,但期望允许调整大小的IList<T>
实现将实现后一个接口,而那些不允许调整大小不会实现它。如果他们这样做,需要能够调整列表大小的代码可能需要IList<T>
(在这种情况下它不接受数组),而不需要调整列表大小的代码可能需要{{1} 1}})。不幸的是,微软并没有做那样的事情,所以代码不可能在编译时要求一个可调整大小的列表 - 如果传入的列表将自己报告为固定大小,它所能做的只是发出尖叫声。