2010-01-29 15 views
33

Estoy usando el contenedor Unity IoC para resolver mis objetos. Sin embargo, me encontré con un problema. Cuando tengo más de un constructor, ¿cómo sabe Unity cuál usar? Parece usar el que tiene parámetros cuando tengo uno con y sin él. ¿Puedo decir explícitamente qué constructor usar?Especifique el constructor para el contenedor Unity IoC para usar

Específicamente tuve una carcasa similar a la siguiente clase Person con dos constructores. En este caso, quiero que el contenedor IoC use el constructor predeterminado, sin parámetros, pero elige el que tiene los parámetros.

public class SomeValueObject 
{ 
    public SomeValueObject(string name) 
    { 
     Name = name; 
    } 
    public string Name { get; set; } 
} 

public class Person 
{ 
    private string _name; 

    public Person() 
    { 
     _name = string.Empty; 
    } 

    public Person(SomeValueObject obj) 
    { 
     _name = obj.Name; 
    } 
} 

Obviamente, esto falla, ya que no se puede crear el SomeValueObject - sin saber qué inyectar a su parámetro de cadena. El error que da es:

Resolución de la dependencia fallida, type = "MyApp.Person", name = "". El mensaje de excepción es: La operación de compilación actual (clave de compilación Build Key [MyApp.Person, null]) falló: El parámetro obj no se pudo resolver al intentar llamar al constructor MyApp.Person (MyApp.SomeValueObject obj). (Tipo de estrategia de BuildPlanStrategy, índice 3)

El registro contenedor:

Container.RegisterType<Person, Person>(new Microsoft.Practices.Unity.ContainerControlledLifetimeManager()); 

Y la resolución de:

var person = Container.Resolve<Person>(); 
+0

¿No es el objetivo de IoC utilizar interfaces? – Martin

+3

Claro, y lo hago principalmente. Pero esto no hizo la diferencia para la pregunta. – stiank81

+0

@Martin Muchos programadores usan clases y evitan la falsa generalidad de crear una interfaz y luego solo tener una implementación de la misma. También evita las acumulaciones de cableado IoC desagradable que ves en la mayoría de las aplicaciones empresariales, pero aún te permite cambiar algunas implementaciones cuando sea necesario. http://programmers.stackexchange.com/questions/133471/writing-testable-code-vs-avoiding-speculative-generality –

Respuesta

46

Puedes verlo esta forma:

container.RegisterType<Person>(new InjectionConstructor()); 

Puedes añadir el LifetimeManager así el uso de una sobrecarga del método RegisterType.

Dicho esto, al modelar para DI, su vida será mucho más fácil si tiene elementos no ambiguos (es decir, no hay constructores sobrecargados).

+0

¿A qué sobrecarga está haciendo referencia? – Casey

+0

@Casey ... Creo que el constructor vacío. – granadaCoder

+0

Como no hay argumentos para InjectionConstructor, está llamando al constructor vacío de Person. Si el código hubiera sido 'nuevo InjectionConstructor (nuevo SomeValueObject ("John Smith"))', eso habría llamado al (otro) constructor de Persona, donde el "otro" constructor es el que usa el objeto/argumento SomeValueObject. – granadaCoder

4

Multiple-Constructor Injection Using an Attribute

Cuando una clase de destino contiene más de un constructor w on el mismo número de parámetros , debe aplicar el atributo InjectionConstructor al constructor que el contenedor Unidad utilizará para indicar qué constructor el contenedor debe utilizar. Al igual que con inyección constructor automático, puede especificar los parámetros del constructor como un tipo concreto, o puede especificar una interfaz o clase base para que el recipiente Unidad contiene un mapeo registrado.

22

De forma predeterminada, Unity elige un constructor con un número máximo de argumentos. Para anular esto, decore el constructor requerido con InjectionConstructorAttribute.

+4

Debemos mencionar que la decoración del constructor acopla el componente a Unity como su contenedor IoC. Es probable que sea preferible manejar la especificación durante el registro, de modo que los componentes no necesiten hacer una referencia a Unity y, por lo tanto, un IoC diferente podría intercambiarse si así lo desea. –

0

Realmente tengo que señalar que la forma en que está usando la inyección de dependencia en este caso es simplemente incorrecta. El contenedor debería poder inyectar SomeValueObject en la construcción.

Lo que probablemente deba hacer es registrar un objeto predeterminado de SomeValueObject que el.La propiedad de nombre devuelve string.Empty en su lugar.

+0

Tal vez mi ejemplo simple está un poco apagado, pero hay una necesidad de dos constructores diferentes en el código real ... Gracias por mencionarlo de todos modos. – stiank81

+0

¿Qué pasa si no lo has escrito? – Casey

Cuestiones relacionadas