Domanda

Di recente ho iniziato a utilizzare un IoC per la prima volta, ma io ' non sono istruito sulle migliori pratiche per usarlo. Più specificamente sto usando Unity in un progetto C # .NET, e ho iniziato a usarlo perché fornito con Prism .

Uso il contenitore per risolvere " livello superiore " oggetti e ottengono gli oggetti corretti iniettati in base al contenitore. Tuttavia, non riesco a vedere chiaramente le migliori pratiche quando ho un oggetto con bambini e bambini piccoli e ho bisogno di alcuni dati dal contenitore IoC fino in fondo, ma non nel mezzo. Come organizzi in genere l'uso del contenitore IoC?

Inizialmente, penserei che passeresti il ??contenitore ovunque sia necessario invece di estrarre i dati necessari dal contenitore di livello superiore e passare questi dati. Ma poi di nuovo ottengo problemi quando raggiungo oggetti che prendono altri dati specifici oltre alle interfacce iniettate, e preferirei non iniettarli attraverso proprietà o metodi init dopo aver risolto l'oggetto.

Spero che sia stato abbastanza chiaro, ma diamo un'occhiata a un esempio immaginario (e leggermente stupido ..).

class Employee
{
    private ICommands _commands; 
    priate List<Customer> _customers = new List<Customer>(); 
    public Employee(ICommands commands)
    {
        _commands = commands; 
    }
    public void AddCustomer(string customerName)
    {
        var customer = new Customer(customerName, _commands); 
        _customers.Add(customer); 
    }
}

class Customer 
{
    private string _name; 
    private ICommands _commands; 
    priate List<Case> _cases = new List<Case>(); 
    public Customer(string, name, ICommands commands)
    {
        _name = name; 
        _commands = commands; 
    }
    public void AddCase()
    {
        var case = new Case(_commands); 
        _cases.Add(case); 
    }
}

class Case    {
    private ICommands _commands; 
    public Customer(ICommands commands)
    {
        _commands = commands; 
    }
    public void TriggerCommands()
    {
        _command.TriggerSomething(); 
    }
}

Quindi, questo esempio non ha molto senso, ma l'essenza è la stessa di ciò che devo fare. Ho alcuni comandi dell'applicazione che passo attraverso le mie classi ViewModel, perché alcuni di essi devono essere in grado di attivare i comandi per visualizzare qualcosa. Ho anche uno spazio di archiviazione comune, ecc. Che potrebbe essere necessario per alcune classi ma attualmente viene passato e archiviato nelle classi medie. Con solo comandi non è un grosso problema se si memorizzano comandi o container, ma uno in un tipico utilizzo IoC passerebbe invece al contenitore IoC e lo userebbe per risolvere oggetti lungo la linea? E che dire di dati specifici come il nome del cliente? Non puoi semplicemente passare questo sul Resolve (), quindi devi iniettarlo in seguito?

Mi dispiace: questo è stato il più breve possibile. Non richiederà risposte della stessa lunghezza ;-) .. Solo; qual è la migliore pratica di fare cose del genere con i contenitori IoC?

È stato utile?

Soluzione

Non sono sicuro di aver capito la tua domanda. Ma non credo che dovresti passare il container. È molto più semplice creare una classe wrapper per il contenitore. Ad esempio:

public class IoCContainer
{
  private static ContainerType = null;

  public static ContainerType Instance 
  {
    get 
    {
      if (_container == null)
      {
        string configFileName = ConfigurationManager.AppSettings[ConfigFileAppSettingName];
        _container = new WindsorContainer(new XmlInterpreter(configFileName));
      }

      return _container;
    }
  }
}

Ora lo chiami ovunque nel tuo codice.

IoCContainer.Instance.Resolve<IAwesomeService>(); 

Questo ti aiuta?

Altri suggerimenti

Non sono sicuro che questo risponda alla tua domanda, ma direi che un buon modo per agire su un'applicazione utilizzando il contenitore Unity (applicabile anche ad altri motori IoC credo) è:

  • Progetta le tue lezioni in modo che tutte le dipendenze richieste sono specificate nel costruttore. In questo modo tu non è necessario affrontare esplicitamente Unità a meno che non sia necessario crearne di nuovi oggetti.
  • Se è necessario creare nuovi oggetti all'interno delle tue classi, passa l'Unità contenitore stesso nel costruttore pure (come riferimento a IUnityContainer ) e crea tutto nuovo istanze di oggetti utilizzando Resolve metodo. Anche per oggetti che non lo sono registrato e non hanno dipendenze, il contenitore ti darà un vero istanza e successivamente è possibile decidere di registrare tipi che non erano stati precedentemente registrati, senza modificare il codice client.
  • Per quanto riguarda il passaggio di valori espliciti agli oggetti risolti, è possibile specificare membri di iniezione concreta quando si registrano i tipi (vedere il parametro InjectionMembers nella classe RegisterType ).

Sembra che tu debba dichiarare fabbriche per le tue entità. Risolvi gli stabilimenti tramite l'iniezione del costruttore e passa i valori dei dati tramite il metodo Create. Tutte le altre dipendenze devono essere risolte tramite il costruttore della fabbrica.

Vedi questa risposta.

Definirei un IoC di classe statica, che può essere inizializzato con un contenitore particolare e implementare metodi come Resolve, Resolve (...), che a loro volta delegano il lavoro effettivo all'istanza del contenitore (lo memorizzerò istanza in un campo o proprietà). In questo modo non devi passare nulla, basta usare

IoC.Resolve<SomeType>();

ovunque nel tuo codice.

Per quanto riguarda i dati specifici: alcuni contenitori accettano un parametro e si risolvono in base a questo parametro (Autofac ha questo tipo di funzionalità). Oppure puoi sempre creare una classe factory che avrà un metodo che accetta un set di parametri (come il nome del cliente) e restituisce un'istanza dell'oggetto corrispondente.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top