2010-03-18 6 views
31

Dada una clase con varios constructores: ¿cómo puedo decirle a Resolve qué constructor usar?¿Cómo sabe Unity.Resolve qué constructor usar?

Considérese la siguiente clase de ejemplo:

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

Si quiero crear un objeto de tipo Foo usando Resolver cómo resolverá saber qué constructor de usar? ¿Y cómo puedo decirle que use el correcto? Digamos que tengo un contenedor con un IBar registrado. ¿Entenderá que debería favorecer al constructor que toma IBar? Y si especifico una cadena también, ¿usará el constructor (string, IBar)?

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

Y por favor, ignora el hecho de que probablemente sería más fácil si la clase acaba de tener un único constructor ...

Respuesta

53

Cuando una clase de destino contiene más de un constructor, la unidad utilizará la que tiene el atributo InjectionConstructor aplicado. Si hay más de un constructor y ninguno lleva el atributo InjectionConstructor, Unity usará el constructor con la mayoría de los parámetros. Si hay más de un constructor de este tipo (más de uno de los "más largos" con el mismo número de parámetros), Unity generará una excepción.

Tomado de link text

+0

Genial. Gracias..! – stiank81

+0

¡Exactamente lo que estaba buscando! Acabo de decorar el constructor que quiero usar con [InjectionConstructor] –

+2

Esa es la respuesta que salvaría un fin de semana. Bien definido –

28

Cuando se registra el tipo, puede especificar qué constructor de usar de esta manera:

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

El código anterior es de la memoria, pero eso es el principio general. En este caso, elegí el constructor que toma un único parámetro de tipo IBar.

Y por favor, ignora el hecho de que probablemente sería más fácil si la clase acaba de tener un único constructor ...

que no se puede ignorar esto. Cuando se trata de la inyección de constructor, ambigüedad es un olor de diseño. Básicamente estás diciendo: Realmente no sé si me importa esta dependencia o no.

Claro, es probable que Unity lo resuelva, pero entonces confiaría en un comportamiento de contenedor específico en lugar de diseñar su API correctamente. Otros contenedores pueden tener un comportamiento diferente, por lo que si alguna vez decide migrar de Unity a un contenedor mejor, pueden ocurrir errores sutiles.

Es mucho más seguro escribir su código de una manera DI-friendly, but container-agnostic.

+0

¡Gracias! Pero, ¿realmente necesito registrar el tipo en el contenedor? Usaré el contenedor para resolver las instancias de Foo, pero no necesito que Foo esté en el contenedor. ¿Pero aún debería usar RegisterType?¿O solo porque tengo esta necesidad específica de decirle qué constructor usar? – stiank81

+0

Sí y no. Como se cita en ozczecho, Unity usa un enfoque heurístico para elegir un constructor ante la ambigüedad (elige el constructor con la mayoría de los parámetros). Si necesita desviarse de este algoritmo, debe indicarlo explícitamente. Una forma es aplicar el atributo InjectionConstructor y otra es registrarlo en el contenedor. Personalmente prefiero registrar el tipo en el contenedor, porque eso me permite mantener mi código contenedor-agnóstico. También permite diferentes configuraciones de contenedores, si corresponde. –

+0

FWIW, la capacidad de Unity para resolver tipos de concreto incluso si no están ya registrados en el contenedor es una característica particular del mismo. Algunos contenedores admiten esa característica, mientras que otros no. –

Cuestiones relacionadas