2010-12-14 8 views
21

En question acerca de la utilidad de la COI de contenedores, el remitente ganar mencionó que con un contenedor IoC se puede tomar esto:Código de Cruft. COI al rescate

public class UglyCustomer : INotifyPropertyChanged 
{ 
    private string _firstName; 
    public string FirstName 
    { 
     get { return _firstName; } 
     set 
     { 
      string oldValue = _firstName; 
      _firstName = value; 
      if(oldValue != value) 
       OnPropertyChanged("FirstName"); 
     } 
    } 

    private string _lastName; 
    public string LastName 
    { 
     get { return _lastName; } 
     set 
     { 
      string oldValue = value; 
      _lastName = value; 
      if(oldValue != value) 
       OnPropertyChanged("LastName"); 
     } 
    } 
} 

a esto:

var bindingFriendlyInstance = IoC.Resolve<Customer>(new NotifyPropertyChangedWrapper()); 

Preguntas:

  • ¿Qué contenedor mágico de IoC proporciona esta bondad?
  • ¿Un ejemplo para implementar esto?
  • ¿Alguna desventaja?
  • En un proyecto con dependencias complejas, ¿estaré llorando cuando intente aplicar el enlace de datos a estos objetos?
+1

Estoy bastante seguro de que la respuesta es solo molestarte con una "idea" en lugar de una implementación real. –

+1

@chibacity. En ese caso, Ben Scheirman es un mejor provocador que cualquier prostituta que haya visto. (En una película, por supuesto). – AngryHacker

+0

si necesitara un Cliente sin lógica, pero con DTO puro y notificaciones de cambio de propiedad, sería mejor declararlo como una interfaz, ICustomer, y no es gran cosa crear una clase concreta con generación de código dinámico. –

Respuesta

9

Para su segundo fragmento de código funcione, NotifyPropertyChangedWrapper sería sin duda tendrá que utilizar la reflexión (o dynamic) para generar una clase que proporciona una interfaz compatible con Customer e implementa la notificación automática de la propiedad. No debería haber problemas de enlace de datos, pero habría un poco de sobrecarga.

Una implementación simplificada que utiliza un objeto dinámico podría ser algo como esto:

public class NotifyPropertyChangedWrapper<T> 
    : DynamicObject, INotifyPropertyChanged 
{ 
    private T _obj; 

    public NotifyPropertyChangedWrapper(T obj) 
    { 
     _obj = obj; 
    } 

    public override bool TryGetMember(
     GetMemberBinder binder, out object result) 
    { 
     result = typeof(T).GetProperty(binder.Name).GetValue(_obj); 
     return true; 
    } 

    // If you try to set a value of a property that is 
    // not defined in the class, this method is called. 
    public override bool TrySetMember(
     SetMemberBinder binder, object value) 
    { 
     typeof(T).GetProperty(binder.Name).SetValue(_obj, value); 
     OnPropertyChanged(binder.Name); 
     return true; 
    } 

    // Implement OnPropertyChanged... 
} 

Obviamente, cualquier código que consume uno de estos objetos perderían cualquier tipo de seguridad estática. La otra opción es generar una clase que implemente la misma interfaz que la clase que se envuelve. Hay muchos ejemplos para esto en la web. El requisito principal es que su Customer debería ser interface o necesitaría que todas sus propiedades fueran virtuales.

+0

sí, si necesitaras un cliente sin lógica, pero DTO puro y notificaciones de cambio de propiedad, sería mejor declararlo como una interfaz, ICustomer, y ese tipo de construcción no es tan grande como para crear una clase concreta con generación de código dinámico. –

+0

¿De todos modos para hacer esto sin el DynamicObject? Estoy en .NET 3.5. Y no renunciar a Intellisense. – AngryHacker

+0

Tendría que hacer lo que dijo Pauli. Ya he hecho esto antes, pero el código es largo y no lo tengo disponible. Aquí hay un artículo donde alguien más hace esto: http://grahammurray.wordpress.com/2010/04/13/dynamically-generating-types-to-implement-inotifypropertychanged/ – Jacob

2

Nunca lo he usado, pero supuestamente puedes crear algo como esto usando PostSharp.

3

Para hacer esto de forma genérica (es decir, una única pieza de código que implementa INotifyPropertyChanged para cualquier clase) use un proxy. Hay muchas implementaciones para hacer esto con Castle.DynamicProxy o LinFu o Unity. Estas bibliotecas proxy tienen un buen soporte en contenedores IoC, por ejemplo, DynamicProxy tiene una buena integración con Castle Windsor y la intercepción de Unity (o como se llame) obviamente tiene una buena integración con el contenedor Unity.

1

Si está buscando una solución específica para la autogeneración de objetos enlazables, debe consultar PropertyChanged.Fody (anteriormente NotifyPropertyWeaver). Esto reescribe las clases que implementan INotifyPropertyChanged para incluir el código de notificación. Hay un ejemplo en la página de github.

En mi opinión, esto es más nítido que usar la solución propuesta de contenedor IOC. Sin embargo, es una biblioteca específica para el enlace INotifyPropertyChanged, por lo que no se aplica como una solución general, como se discutió en su pregunta vinculada.

+0

La pregunta era específicamente sobre qué *** contenedor de COI *** proporcionaba esa característica. No abra una pregunta de dos años *** que tenga una respuesta aceptada ** con una respuesta que realmente no aborde la pregunta. – jgauffin

+0

Interpreté esta pregunta para que se relacionara con la reducción del código cruft, estaba respondiendo desde esa perspectiva. Creo que el enfoque del COI se debe principalmente a que se inspiró en otra pregunta del COI. Incluso si mi respuesta no utiliza el COI, creo que es valioso señalar que otras técnicas pueden ser más adecuadas para lograr el resultado deseado. Además, [esta pregunta en meta] (http://meta.stackexchange.com/questions/20524/reviving-old-questions) concluye que responder viejas preguntas está bien. –

Cuestiones relacionadas