2010-03-18 4 views
31

Data una classe con diversi costruttori: come posso dire a Resolve quale costruttore utilizzare?In che modo Unity.Resolve sa quale costruttore usare?

Si consideri il seguente classe di esempio:

public class Foo 
{ 
    public Foo() { } 
    public Foo(IBar bar) 
    { 
     Bar = bar; 
    } 
    public Foo(string name, IBar bar) 
    { 
     Bar = bar; 
     Name = name; 
    } 
    public IBar Bar { get; set; }   
    public string Name { get; set; } 
} 

Se voglio creare un oggetto di tipo Foo usando Resolve come si risolverà sapere quale costruttore da usare? E come posso dire di usare quello giusto? Diciamo che ho un container con un IBar registrato - capirà che dovrebbe favorire il costruttore che prende IBar? E se specifico anche una stringa, userà il costruttore (string, IBar)?

Foo foo = unityContainer.Resolve<Foo>(); 

E vi prego di ignorare il fatto che probabilmente sarebbe più facile se la classe appena avuto un singolo costruttore ...

risposta

53

Quando una classe di destinazione contiene più di un costruttore, Unità li utilizzerà il a cui è stato applicato l'attributo InjectionConstructor. Se c'è più di un costruttore e nessuno porta l'attributo InjectionConstructor, Unity utilizzerà il costruttore con il maggior numero di parametri. Se c'è più di un tale costruttore (più di uno dei "più lunghi" con lo stesso numero di parametri), Unity solleverà un'eccezione.

Tratto da link text

+0

Grande. Grazie..! – stiank81

+0

Esattamente quello che stavo cercando! Ho appena decorato il costruttore che voglio usare con [InjectionConstructor] –

+2

Questa è la risposta che salverebbe un weekend. Ben definito. –

28

Quando si registra il tipo, è possibile specificare quale costruttore da utilizzare in questo modo:

container.RegisterType<Foo>(
    new InjectionConstructor(
     new ResolvedParameter<IBar>())); 

Il codice di cui sopra è dalla memoria, ma questo è il principio generale. In questo caso ho scelto il costruttore che accetta un singolo parametro di tipo IBar.

E vi prego di ignorare il fatto che probabilmente sarebbe più facile se la classe appena avuto un singolo costruttore ...

non posso ignorare questo. Quando si tratta di Iniezione del Costruttore, l'ambiguità è un odore di design. In pratica stai dicendo: Non so davvero se mi interessa questa dipendenza o meno.

Certo, Unity è probabile che capisca per te, ma poi si sarebbe affidamento su un comportamento specifico contenitore invece di progettare correttamente la tua API. Altri contenitori potrebbero avere un comportamento diverso, quindi se si sceglie di migrare da Unity a un contenitore migliore, potrebbero verificarsi piccoli bug.

È molto più sicuro scrivere il codice in un modo DI-friendly, but container-agnostic.

+0

Grazie! Ma ho davvero bisogno di registrare il tipo nel contenitore? Userò il contenitore per risolvere le istanze di Foo, ma non ho bisogno di Foo per essere nel contenitore. Ma dovrei comunque usare RegisterType?O solo perché ho questo specifico bisogno di dirgli quale costruttore usare? – stiank81

+0

Sì e no. Come citato da ozczecho, Unity usa un approccio euristico per scegliere un costruttore di fronte all'ambiguità (sceglie il costruttore con la maggior parte dei parametri). Se hai bisogno di deviare da questo algoritmo, devi dirlo esplicitamente. Un modo è quello di applicare l'attributo InjectionConstructor e un altro è registrarlo nel contenitore. Personalmente preferisco registrare il tipo nel contenitore, perché questo mi consente di mantenere il mio codice agnostico. Consente inoltre diverse configurazioni del contenitore, se applicabile. –

+0

FWIW, la capacità di Unity di risolvere tipi concreti anche se non sono già registrati nel contenitore è una caratteristica particolare. Alcuni contenitori supportano questa funzionalità, mentre altri no. –