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