2010-12-14 9 views
21

In question circa l'utilità di IoC Container, il mittente vincente ha detto che con un contenitore CIO si può prendere questo:Codice di Cruft. CIO di soccorso

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 questo:

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

Domande:

  • Quale magico contenitore IoC fornisce questa bontà?
  • Un esempio di implementazione di questo?
  • Eventuali aspetti negativi?
  • In un progetto con dipendenze complesse, piangerò quando cerco di applicare l'associazione dati a questi oggetti?
+1

Sono quasi sicuro che la risposta ti stuzzica solo con una "idea" piuttosto che un'implementazione reale. –

+1

@chibacity. In tal caso, Ben Scheirman è una presa in giro migliore di qualsiasi prostituta che abbia mai visto. (In un film, ovviamente). – AngryHacker

+0

se fosse necessario un Cliente privo di logica ma pura DTO e notifiche di modifica delle proprietà sarebbe meglio dichiararlo come un'interfaccia, ICustomer, e non è un grosso problema per creare una classe concreta con generazione di codice dinamica. –

risposta

9

Per il secondo frammento di codice a lavorare, NotifyPropertyChangedWrapper sarebbe certamente necessario utilizzare riflessione (o dynamic) per generare una classe che fornisce un'interfaccia compatibile con Customer ed implementa la notifica di proprietà automatica. Non ci dovrebbero essere problemi di associazione dei dati, ma ci sarebbe un piccolo sovraccarico.

Un'implementazione semplificata che utilizza un oggetto dinamico potrebbe essere simile a questo:

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... 
} 

Ovviamente, qualsiasi codice che consuma uno di questi oggetti perderebbe qualsiasi tipo di sicurezza statica. L'altra opzione è quella di generare una classe che implementa la stessa interfaccia della classe in corso di wrapping. Ci sono molti esempi per questo sul web. Il requisito principale è che il tuo Customer debba essere uno interface o che abbia bisogno che tutte le sue proprietà siano virtuali.

+0

sì, se tu avessi bisogno di un Cliente privo di logica, ma pura DTO e notifiche di modifica del caso, sarebbe meglio dichiararlo come un'interfaccia, ICustomer, e quindi un tale costrutto non è un grosso problema per creare una classe concreta con generazione di codice dinamico. –

+0

Ad ogni modo per fare ciò senza DynamicObject? Sono su .NET 3.5. E non rinunciando ad Intellisense. – AngryHacker

+0

Dovresti fare quello che ha detto Pauli. L'ho già fatto prima, ma il codice è lungo e non ce l'ho disponibile. Ecco un articolo in cui qualcun altro fa questo: http://grahammurray.wordpress.com/2010/04/13/dynamically-generating-types-to-implement-inotifypropertychanged/ – Jacob

2

Non l'ho mai usato, ma si può presumibilmente creare qualcosa di simile usando PostSharp.

3

Per fare ciò in modo generico (vale a dire un singolo pezzo di codice che implementa INotifyPropertyChanged per qualsiasi classe) utilizzare un proxy. Esistono molte implementazioni per fare ciò con Castle.DynamicProxy o LinFu o Unity. Queste librerie proxy hanno un buon supporto nei contenitori IoC, ad esempio DynamicProxy ha una buona integrazione con Castle Windsor e l'intercettazione Unity (o come si chiama) ha ovviamente una buona integrazione con il contenitore Unity.

1

Se si sta cercando una soluzione specifica per la creazione automatica di oggetti collegabili, consultare PropertyChanged.Fody (in precedenza NotifyPropertyWeaver). Questo riscrive le classi che implementano INotifyPropertyChanged per includere il codice di notifica. C'è un esempio nella pagina di github.

A mio parere, questo è più ordinato rispetto all'utilizzo della soluzione di contenitore IOC proposta. Tuttavia, è una libreria specifica per l'associazione INotifyPropertyChanged, quindi non è applicabile come soluzione generale, come è stato discusso nella domanda collegata.

+0

La domanda chiedeva specificamente quale *** contenitore *** IOC forniva quella funzionalità. Non aprire una domanda di due anni *** che ha una risposta accettata ** con una risposta che non risolve veramente la domanda. – jgauffin

+0

Ho interpretato questa domanda come correlata riducendo il codice cruft, stavo rispondendo da quella prospettiva. Penso che l'attenzione del CIO sia principalmente perché è stata ispirata da un'altra domanda del CIO. Anche se la mia risposta non utilizza il CIO, ritengo sia importante sottolineare che altre tecniche potrebbero essere più adatte a raggiungere il risultato desiderato. Inoltre, [questa domanda su meta] (http://meta.stackexchange.com/questions/20524/reviving-old-questions) conclude che rispondere alle vecchie domande è ok. –