Domanda

Sto usando C# con l'Unity Framework di Microsoft. Non sono del tutto sicuro di come risolvere questo problema. Probabilmente ha qualcosa a che fare con la mia mancanza di comprensione DI con l'unità.

Il mio problema può essere riassunto utilizzando il seguente codice di esempio:

class Train(Person p) { ... }

class Bus(Person p) { ... }

class Person(string name) { ... }

Person dad = new Person("joe");
Person son = new Person("timmy");

Quando chiamo il metodo Resolve su Bus, come posso essere sicuro che il "figlio" della persona con il nome "Timmy" sia iniettato e quando risolvo il treno come posso essere sicuro che quella persona "papà" con allora il nome "Joe" sia risolto?

Sto pensando forse a usare istanze nominate? Ma sono in perdita. Qualsiasi aiuto sarebbe apprezzato.

A parte questo, preferirei non creare un'interfaccia iPerson.

È stato utile?

Soluzione

Un modo per risolvere questo sarebbe quello di utilizzare un costruttore di iniezione con una registrazione nominata.

// Register timmy this way  
Person son = new Person("Timmy");  
container.RegisterInstance<Person>("son", son);  

// OR register timmy this way  
container.RegisterType<Person>("son", new InjectionConstructor("Timmy"));  

// Either way, register bus this way.  
container.RegisterType<Bus>(new InjectionConstructor(container.Resolve<Person>("son")));  

// Repeat for Joe / Train

Altri suggerimenti

A meno che non ti registri rispettivamente "Joe" e "Timmy" come dipendenze denominate, non si può essere sicuri che "Timmy" sia iniettato in Schoolbus. In effetti, se si tenta di registrare due istanze della stessa classe delle dipendenze senza nome, avrai una configurazione ambigua e non sarai in grado di risolvere Person affatto.

In generale, se devi registrare molte istanze nominate, probabilmente stai andando in modo sbagliato. L'idea principale di DI è risolvere Servizi di dominio più di Oggetti di dominio.

L'idea principale di DI è quella di fornire un meccanismo che consente di risolvere Tipi astratti (interfacce o classi astratte) in tipi di cemento. Il tuo esempio non ha tipi astratti, quindi non ha molto senso.

Mark Seeman ha capito bene. E sono solidale con la tua confusione. L'ho attraversato da solo quando ho imparato a utilizzare contenitori per iniezione di dipendenza automatica. Il problema è che ci sono molti modi validi e ragionevoli per progettare e utilizzare oggetti. Tuttavia, solo alcuni di questi approcci funzionano con contenitori di iniettori di dipendenza automatica.

La mia storia personale: ho imparato i principi OO di costruzione di oggetti e inversione del controllo molto prima di imparare a usare l'inversione di contenitori di controllo come i contenitori unità o il castello Windsor. Ho acquisito l'abitudine di scrivere codice come questo:

public class Foo
{
   IService _service;
   int _accountNumber;

   public Foo(IService service, int accountNumber)
   {
      _service = service;
      _accountNumber = accountNumber;
   }
   public void SaveAccount()
   {
       _service.Save(_accountNumber);

   }
}
public class Program
{
     public static void Main()
     {
        Foo foo = new Foo(new Service(),1234);
        foo.Save();
     }
}

In questo progetto, la mia classe Foo è responsabile del salvataggio degli account nel database. Ha bisogno di un numero di conto per farlo e un servizio per fare il lavoro sporco. Questo è in qualche modo simile alle classi concrete che hai fornito sopra, in cui ogni oggetto prende alcuni valori unici nel costruttore. Funziona bene quando si istanzia gli oggetti con il tuo codice. Puoi passare i valori appropriati al momento giusto.

Tuttavia, quando ho appreso i contenitori di iniezione di dipendenza automatica, ho scoperto che non stavo più istanziando Foo a mano. Il contenitore basta l'istanza degli argomenti del costruttore per me. Questa è stata una grande comodità per i servizi come Iservizio. Ma ovviamente non funziona così bene per numeri interi e stringhe e simili. In quei casi, fornirebbe un valore predefinito (come zero per un numero intero). Invece, ero abituato a passare valori specifici del contesto come il numero di conto, il nome, ecc ... quindi ho dovuto regolare il mio stile di codifica e design per essere così:

public class Foo
{
   IService _service;
   public Foo(IService service)
   {
      _service = service;
   }
   public void SaveAccount(int accountNumber)
   {
       _service.Save(accountNumber);

   }
}
public class Program
{
     public static void Main()
     {
        Foo foo = new Foo(new Service());
        foo.Save(1234);
     }
}

Sembra che entrambe le classi FOO siano design validi. Ma il secondo è utilizzabile con l'iniezione di dipendenza automatica e la prima no.

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