2009-09-08 25 views
6

La interfaz IList requiere un método Add. Las matrices implementan esta función pero simplemente arroja una NotImplementedException. Esto me parece un diseño muy malo.¿Por qué las matrices admiten IList?

¿Qué pensaban los diseñadores cuando hacían esto?

Respuesta

7

ILists pueden ser de solo lectura: si tiene dudas, la persona que llama puede probar la propiedad IsFixedSize antes de intentar agregar o eliminar un elemento, o la propiedad IsReadOnly antes de intentar modificar un elemento.

Una matriz es un IList de tamaño fijo.

Puede ser conveniente poder tratar una matriz como una lista. Un ejemplo es burlarse de un método de acceso a datos que devuelve un IList: se puede burlar para simplemente devolver un molde de matriz como IList.

+1

En realidad, es la propiedad 'IsFixedSize' la que debe verificar. 'IsReadOnly' será' false' para las matrices porque los elementos existentes se pueden modificar. 'IsFixedSize' será' verdadero' porque los elementos no se pueden agregar o eliminar. – LukeH

+0

Solo para aclarar el problema con solo fijo y de lectura: http://blogs.msdn.com/ericlippert/archive/2009/08/27/what-s-the-difference-between-fixed-and-fixed.aspx – Oliver

+1

@Oliver: soy un gran fanático del blog de Eric Lippert, pero ese artículo no tiene absolutamente nada que ver con las propiedades 'IsFixedSize' o' IsReadOnly'. – LukeH

0

Como es común que diferentes objetos tengan diferentes habilidades, algunas interfaces incluyen miembros que se implementarán en algunas, pero no en todas las implementaciones. Si algunas, pero no todas las implementaciones de una interfaz hipotética IVehicle podrían adjuntar un remolque, un patrón típico sería definir la función de AttachTrailer como "intento de adjuntar un remolque, si CanAttachTrailer es verdadero, o bien arrojar NotSupportedException" . Todas las implementaciones de IVehicle podrían cumplir con la especificación anterior, independientemente de si pueden manejar trailers.

Una ventaja de este enfoque es que es posible que las implementaciones de una interfaz ofrezcan muchas combinaciones diferentes de características, sin tener que definir diferentes tipos para diferentes combinaciones. Otra ventaja de este enfoque es que es posible que un método Foo reciba un objeto que incluye capacidades que Foo no necesita, para pasar ese objeto junto con el método Bar, que necesita esas capacidades, sin requerir ningún tipo de difusión en ningún lugar, y sin Foo sabiendo qué capacidades necesitará Bar. Otra ventaja es que esto hace que sea más fácil escribir código que no necesita ciertas capacidades, pero puede aprovecharlas cuando existen.

Sin embargo, existen algunas desventajas en este enfoque. Todavía no hay forma de que una interfaz especifique implementaciones predeterminadas para cualquier propiedad o método. En consecuencia, incluso las implementaciones IVehicle que no pueden adjuntar trailers necesitarán incluir código para devolver false a la propiedad CanAttachTrailer, y lanzar una excepción en su método AttachTrailer. Además, dado que la interfaz no impone ningún requisito de que se implementen muchos de sus métodos, no hay forma de que un compilador sepa rechazar cuando intenta llamar a una función que requiere una capacidad con un objeto de un tipo que no puede proporcionarla.

Al diseñar IList<T>, Microsoft aparentemente pensó que las ventajas del enfoque de "interfaz de capacidades opcionales" superaban las desventajas. De hecho, si .net proporcionó un medio para que las clases implementen interfaces para diferir a las implementaciones predeterminadas de miembros que no desean proporcionar, habría pocas razones para no incluir muchas capacidades opcionales en las interfaces de nivel base; para permitir la aplicación en tiempo de compilación de las capacidades necesarias, se podrían obtener varias interfaces a partir de una base que incluya todos los miembros necesarios, y especificar que las clases que implementan estas últimas interfaces deben implementar ciertos miembros de maneras que son realmente útiles. Por ejemplo, Microsoft podría haber definido IResizableList<T> para heredar IList<T> sin agregar ningún miembro, pero con la expectativa de que las implementaciones IList<T> que permitieran redimensionar implementarían la última interfaz, mientras que las que no permitían el cambio de tamaño no lo implementarían.Si lo hubieran hecho, el código que necesitaba poder cambiar el tamaño de una lista podría exigir un IResizableList<T> (en cuyo caso no aceptaría una matriz), mientras que el código que no necesitaba cambiar el tamaño de una lista podría exigir un IList<T>). Desafortunadamente, Microsoft no hizo nada de eso, por lo que no es posible que el código exija una lista redimensionable en tiempo de compilación; todo lo que puede hacer es chillar si una lista aprobada se informa a sí misma como de tamaño fijo.

Cuestiones relacionadas