2011-07-07 11 views
8

Tengo una subclase de List<Location> llamada LocationList. Esta es una manera conveniente para nosotros agregamos otras propiedades (como IsExpanded y tal que podemos utilizar en la interfaz de usuario. Bastante bien. Pero ahora, queremos que cada lugar para estar al tanto de su matriz. Como tal, tenemos que ser notificado cuando algo que se añade a LocationList, pero no se puede anular Add y Remove. si bien podemos utilizar ObservableCollection, eso es más de un Vista/ViewModel construir. se trata de los datos del modelo puros.¿Cómo puedo detectar las adiciones a una lista genérica en C# 4.0?

seguro de que podríamos establecer manualmente el padre al añadir a la colección, pero odio la lógica no automatizada así porque no hay nada para aplicar correctamente su conjunto. Dejar que la colección (bueno, la Lista) diga automáticamente 'Hola ... te están agregando, así que estableceré tu padres a la clase que es mi dueño ". es lo que busco.

Mi idea es que en lugar de subclase List<Location> crear sólo una clase en lugar recta que utiliza una List<Location> internamente, y luego simplemente me puedo exponer mi propia Agregar/Quitar métodos y manejar las adaptaciones de 'padre' en ese país. Sin embargo, al hacerlo se rompe la posibilidad de enumerar sobre la colección interna ya que está adentro.

Dicho esto, ¿hay alguna manera ya sea escuchar a cambios List<Location>, o al menos delegar su interfaz IEnumerable del objeto envuelto a su envoltura?

Respuesta

8

Cambiar la LocationList heredar de Collection<Location> lugar. No sé por qué List<T> no está sellado, pero no es extensible.

Fuente: Pautas de diseño de la estructura, segunda edición, página 251:

List<T> está optimizado para el rendimiento y la potencia en el coste de la limpieza de las APIs y flexibilidad.

+0

Esto parece ser el más fácil de implementar ... simplemente cambiando la Lista a la Colección que no agrega todos los gastos generales de ObservableCollection aunque se pierde un poco de rendimiento en comparación con la Lista . Aún así, eso es más que suficiente para que puedas obtener el voto. ¡Gracias! – MarqueIV

4

List<T> ha protegido a miembros InsertItem<T>RemoveItem<T>, etc., que se puede anular en su clase derivada a hacer lo que quiera.

** ACTUALIZACIÓN **

En realidad lo anterior es incorrecta, es Collection<T> que tiene estos métodos protegidos. En general, al derivar clases de Lista personalizadas, se recomienda derivar de Collection<T> en lugar de List<T>.

Ver this answer.

+1

Si va a sobrescribir InsertItem/RemoveItem, ¿por qué no utiliza una versión en la que el trabajo ya está hecho (ObservableCollection) –

+0

ObservableCollection está realmente optimizado para ViewModel más que el modelo. La única persona que necesita estar al tanto del cambio es la colección en sí misma. No necesita la sobrecarga de notificación de cambio completa. – MarqueIV

+1

@MarqueIV: "No puedo aceptar tu respuesta por otros once minutos", tan bien como la respuesta inicial fue incorrecta, demasiado rápido. ¡Mira la actualización y acepta la respuesta de Michael Stum! – Joe

0

Sin embargo, al hacerlo se rompe ser capaz de enumerar más de la colección interna, ya que hay dentro.

Esto no es cierto suponiendo que sigue la técnica adecuada y poner en práctica IEnumerable y ICollection

Pero yo usaría colección observable en lugar de reinventar la rueda.

Y, por supuesto, puede utilizar Reactive extensions para hacer lo que necesita.

+0

No creo que necesite ICollection. Creo que IEnumerable es suficiente. Dicho esto, parece que la respuesta de @Anthony Pegram es la que maneja ese caso ... simplemente delegue en la colección interna. Sin embargo, simplemente cambiar la clase base de la lista a la colección parece ser el truco, así que ese es el que estoy marcando. – MarqueIV

2

Mi idea es que en lugar de lista subclase crear sólo lugar una clase recta que utiliza una lista internamente, y luego me simplemente puedo exponer mi propia Agregar/Quitar métodos y manejar los ajustes a 'Padre' allí. Sin embargo, al hacerlo se rompe la posibilidad de enumerar más de la colección interna ya que es dentro.

Aún puede implementar IEnumerable<Location> en su colección personalizada. Use List<> como el detalle de implementación interno de la clase, y puede permitir la enumeración a través de la interfaz.

class LocationList : IEnumerable<Location> 
{ 
    List<Location> _list; // initialize somewhere 

    public IEnumerator<Location> GetEnumerator() 
    { 
     return _list.GetEnumerator(); 
    } 

    IEnumerable.IEnumerator GetEnumerator() 
    { 
     return this.GetEnumerator(); 
    } 

    // ... your other custom properties and methods 
} 
+1

Mejor podría ser implementar IList , que incluye IEnumerable , pero también permite su uso en contextos que pueden querer una lista o, como mínimo, una colección. – siride

+0

@siride, seguro, él puede implementar el más robusto 'IList '. Viene con una funcionalidad adicional que él puede o no querer proporcionar. El punto no era específicamente qué interfaz tenía que implementar. En verdad, * no tiene que implementar la interfaz en absoluto * (simplemente puede definir un método apropiado 'GetEnumerator'), es simplemente más idiomático hacerlo. –

+0

@Anthony, solo para hacerte saber que estaba a punto de marcar esto como la respuesta, pero parece que la cosa más simple de seguir satisfaciendo todas nuestras necesidades es simplemente cambiarla de la Lista a la Colección , lo que me permite anular Necesito.Aún así, es genial saber que puedo delegar el código de enumeración en la colección interna, así que voté el tuyo. Tendré que pensar si IList vs IEnumerable es mejor ... IList puede ser exagerado para nosotros, ya que en realidad solo estamos interesados ​​en las enumeraciones en su mayor parte, pero poder usarlo donde se usa la lista es genial – MarqueIV

0

O se puede usar Observer pattern

+0

Eso es un poco exagerado por simplemente exponer la interfaz IEnumerable de una colección interna. Si fui con la subclase pura, entonces el gráfico del objeto no se alinea. No parece que ese sea el patrón apropiado para este caso de uso. – MarqueIV

1

Prueba el genérica BindingList<T>, lo que provoca eventos cuando se añaden y eliminan elementos.

+0

Vea mis comentarios sobre ObservableCollection en la respuesta de CanGen arriba. – MarqueIV

+0

@Marque: Te das cuenta de que hay un evento dedicado a elementos que se agregan, y que la colección no detecta cambios (los elementos sí lo hacen, y solo los tipos que implementan INotifyPropertyChanged). Así que creo que esta carga adicional de la que estás preocupado no existe en realidad. La invocación de delegado y la llamada de función virtual cuestan casi exactamente el mismo costo. –

+0

En realidad, cuando invalida Collection en una subclase (List no admite anular la implementación de agregar/eliminar), está interceptando la llamada de mensaje en sí, por lo que la colección base aún no sabe que la llamada se realizó para generar tales notificaciones. ¡Además, la Colección no tiene eventos para recaudar! Para eso sirve ObservableCollection . Y no, los objetos en sí mismos no conocen las colecciones y mucho menos si están en ellas o no, así que tengo que estar respetuosamente en desacuerdo con su evaluación. Simplemente subclases Colección me da lo que estoy buscando. – MarqueIV

Cuestiones relacionadas