2009-02-05 16 views
22

que estoy trabajando en un proyecto en el que se utiliza el marco de la Unidad como el contenedor IoC. Mi pregunta se refiere a la inyección de una dependencia opcional (en este caso un registrador) en varias clases que utilizan la inyección o propiedad-setter.Setter en la Unidad sin atributos

que no quieren el desorden de los constructores de todas mis clases con estas dependencias opcionales, pero no puedo encontrar una buena manera de manejar esto en la Unidad. La forma en que lo haría esto es, de acuerdo con el MSDN documentation, mediante la adición de un atributo de la propiedad:

private ILogger logger; 

[Dependency] 
public ILogger Logger 
{ 
get { return logger; } 
    set { logger = value; } 
} 

Esto me parece muy feo. En StructureMap se podría hacer lo siguiente para configurar todas las propiedades de un tipo determinado:

SetAllProperties(policy => policy.OfType<ILog>()); 

¿Alguien sabe si es posible hacer algo similar en la Unidad?

Editar:

Kim Mayor sugiere el uso de this approach que también se puede lograr a través de código.

estaría interesado en ejemplos de cómo hacer esto automáticamente para todas las propiedades coincidentes.

Respuesta

3

El siguiente tutorial muestra una manera de hacerlo a través de la configuración. Por supuesto, también puede pasarlo por el código. http://aardvarkblogs.wordpress.com/unity-container-tutorials/10-setter-injection/

+0

Gracias por la sugerencia. Supongo que puedo usar esto como una solución alternativa, pero por lo que puedo ver, esto requiere que crees una configuración para cada clase que usa el registrador. Me preguntaba si era una forma de especificar esto una vez, de modo que todas las clases que usan el registrador se inyectaran automáticamente. – LittleBoyLost

+0

No he intentado lo siguiente, así que no estoy seguro. Creo que deberías poder registrar todas tus clases.Luego, reflexione sobre las clases registradas y agregue el registro de inyección del colocador si el tipo tiene un ajustador ILogger. –

18

No me gustan esos atributos también

se pueden realizar todo mediante el método deConfigurar el contenedor de la unidad:

primer registro del tipo

unityContainer.RegisterType<MyInterface,MyImpl>(
        new ContainerControlledLifetimeManager()); 

Si tener varios constructores que tendrá que de esta manera la Unidad invoca al constructor sin parámetros (si no hay ninguno configurado la unidad irá por los más gordos uno)

unityContainer.Configure<InjectedMembers>() 
          .ConfigureInjectionFor<MyImpl>(
           new InjectionConstructor()); 

Configuración de propiedad de dependencia de

unityContainer.Configure<InjectedMembers>() 
        .ConfigureInjectionFor<MyImpl>(
         new InjectionProperty(
          "SomePropertyName", 
           new ResolvedParameter<MyOtherInterface>())); 

Configuración de método de la dependencia

unityContainer.Configure<InjectedMembers>() 
        .ConfigureInjectionFor<MyImpl>(
         new InjectionMethod(
          "SomeMethodName", 
          new ResolvedParameter<YetAnotherInterface>())); 
4

Usted podría intentar esto:

este código en MiClase

[InjectionMethod] 
public void Initialize(
       [Dependency] ILogger logger 

y luego llamándola por:

unitycontainer.BuildUp<MyClass>(new MyClass()); 

unidad luego llamar al método de inicialización con la dependencia del recipiente y entonces u puede guardarlo en una variable privada en MiClase o algo ...

7

El original ejemplo informados se ve muy complicado, pero se puede utilizar propiedades de auto-aplicado como este para ayudar a limpiar ese código de arriba:

[Dependency] 
public ILogger Logger { get; set; } 
16

Asimismo, no soy un gran fan de la utilización atributos, pero me Tampoco me gusta el método .Configure<InjectedMembers>() porque está vinculado a un nombre de propiedad específico y un valor específico. La forma en que he encontrado que te da la mayor flexibilidad es crear tu propia estrategia de desarrollador.

Creé esta clase simple que itera las propiedades de un objeto que se está construyendo y establece sus valores de propiedad si el tipo de esa propiedad se ha registrado con el contenedor de unidad.

public class PropertyInjectionBuilderStrategy:BuilderStrategy 
{ 
    private readonly IUnityContainer _unityContainer; 

    public PropertyInjectionBuilderStrategy(IUnityContainer unityContainer) 
    { 
     _unityContainer = unityContainer; 
    } 

    public override void PreBuildUp(IBuilderContext context) 
    { 
     if(!context.BuildKey.Type.FullName.StartsWith("Microsoft.Practices")) 
     { 
      PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(context.BuildKey.Type); 

      foreach (PropertyDescriptor property in properties) 
      { 
       if(_unityContainer.IsRegistered(property.PropertyType) 
        && property.GetValue(context.Existing) == null) 
       { 
        property.SetValue(context.Existing,_unityContainer.Resolve(property.PropertyType)); 
       } 
      } 
     } 
    } 
} 

registra su BuilderStrategy mediante la creación de un UnityContainerExtension. Aquí está un ejemplo:

public class TestAppUnityContainerExtension:UnityContainerExtension 
{ 
    protected override void Initialize() 
    { 
     Context.Strategies.Add(new PropertyInjectionBuilderStrategy(Container), UnityBuildStage.Initialization); 
    } 
} 

que obtiene registrado en el contenedor de la unidad como tal:

IUnityContainer container = new UnityContainer(); 
container.AddNewExtension<TestAppUnityContainerExtension>(); 

Espero que esto ayude,
Mateo

+0

¡Esa es una buena solución! Yo trabajo bastante bien para lo que quería hacer. Normalmente uso MEF para inyección, pero en una aplicación de consola quiero usar unity, ¡ahora no tengo que marcar todas las propiedades con importaciones unitarias! – lukebuehler

+1

Es una solución muy bien estructurada. Mi única preocupación sería el rendimiento. La función "IsRegistered" intentará realmente resolver cada propiedad pública. Una mejor manera podría ser pasar una lista de tipos para resolver en el constructor de objetos estratégicos y solo tratar de resolver los tipos aceptados. –

+1

Esto no parece funcionar bien en conjunto con PerResolveLifetimeManager ya que está comenzando una nueva "resolución" con cada propiedad inyectada. ¿Alguna idea para una solución alternativa aquí? –

4

Con Unity 2.1 Esto funcionaría así:

var container = new UnityContainer() 
      .RegisterType<ILogger, Logger>() 
      .RegisterType<ISomeInterface, SomeImplementaion>(
           new InjectionProperty("Logger", new ResolvedParameter<ILogger>())); 

La propiedad inyectada de SomeImplementaion clase es solo

public ILogger Logger { get; set; } 
1

Eche un vistazo al proyecto UnityConfiguration para configuración basada en convenciones. Funciona bastante bien, aunque tengo un problema al buscar varias implementaciones usando ResolveAll<IType>(). Ver this Question.

container.RegisterInstance(typeof (ILogger), LoggerService.GetLogger()); 
container.Configure(c => c.Scan(scan => 
        { 
         scan.AssembliesInBaseDirectory(a => a.FullName.StartsWith("My.Company")); // Filter out everthing that are not from my assemblies 
         scan.InternalTypes(); 
         scan.With<SetAllPropertiesConvention>().OfType<ILogger>(); 
        })); 
0

Puede inyectar su clase con el contenedor de la unidad.

por ejemplo, si usted tiene una clase "MyClass" y tiene dependencia de interfaz de dos "IExample1" y "IExample2" y que no desea definir parámetros para ellos en el constructor, a continuación, siga los pasos siguientes

Paso 1. Registro las interfaces en el contenedor de unidad

IUnityContainer container = new UnityContainer(); 
container.RegisterType<IExample1,Impl1>(); 
container.RegisterType<IExample2,Impl2>(); 
//resolve class MyClass 
var myClass = container.Resolve<MyClass>(); 


Paso 2. Su clase debe tener este aspecto

public class MyClass 
{ 
    IExample1 ex1; 
    IExample2 ex2 
    public MyClass(IUnityContainer container) 
    { 
     /* This unity container is same unity container that we used in step 
      1 to register and resolve classes. So you can use this container to resolve 
      all the dependencies. */ 
     ex1= container.Resolve<IExample1>(); // will give you object of Impl1 
     ex2= container.Resolve<IExample2>(); // will give you object of Impl2 
    } 
} 

Paso 3. De esta forma, puede resolver cualquier cantidad de dependencias sin definirlas en el constructor.

+1

@Petter Friberg, gracias por editarlo :) –

Cuestiones relacionadas