2009-07-27 21 views
28

Dado el siguiente código, ¿cómo puedo resolver la SomeInstance correcta en autofac?Resolución de la interfaz genérica con Autofac

public class BaseClass {} 

public class SubClass1 : BaseClass {} 

public class SubClass2 : BaseClass {} 

public interface IGenericInterface<T> where T : BaseClass {} 

public class SomeInstance1<T> : IGenericInterface<T> where T : SubClass1 

public class SomeInstance2<T> : IGenericInterface<T> where T : SubClass2 

Quiero elegir SomeInstance1 o 2 en función del tipo de la genérica sobre las subclases.

Así que, por ejemplo, tengo una colección de subclases (SubClass1, 2 ....) y al iterar sobre ellas quiero elegir la clase SomeInstance correcta.

Respuesta

59

Autofac admite genéricos abiertos. Se puede utilizar el siguiente código si el tipo de medicamentos genéricos se conoce en tiempo de compilación:

var builder = new ContainerBuilder(); 

builder.RegisterGeneric(typeof(SomeInstance1<>)) 
    .As(typeof(IGenericInterface<>));    

var container = builder.Build(); 

var instance1 = container.Resolve<IGenericInterface<SubClass1>>(); 

Assert.IsInstanceOfType(typeof(SomeInstance1<SubClass1>), instance1); 

Si el parámetro de tipo no se conoce hasta tiempo de ejecución (que es probable que su caso si desea recorrer colección de tipos), entonces usted puede construir su tipo usando MakeGenericType:

 var typeInRuntime = typeof (SubClass1); 
     var instance1 = container.Resolve(typeof(IGenericInterface<>).MakeGenericType(typeInRuntime)); 
1

Corrección. No puede llamar a MakeGenericType desde el contenedor. Resolví el problema de instanciar Genéricos usando el 'TIPO' como el parámetro en la llamada Resolver. El constructor está registrado.

 builder.RegisterGeneric(typeof (FakeRepository<>)).As(typeof (IRepository<>)).OnActivating(e => 
     { 
      var typeToLookup = e.Parameters.FirstOrDefault() as TypedParameter; 
      if (typeToLookup != null) 
      { 
       var respositoryType = typeof (FakeRepository<>); 
       Type[] typeArgs = {typeToLookup.Value.GetType()}; 
       var genericType = respositoryType.MakeGenericType(typeArgs); 
       var genericRepository = Activator.CreateInstance(genericType); 
       e.ReplaceInstance(genericRepository); 
      } 
     }); 

Luego la resolución ocurre así, pasando un TypedParameter a la resolución. En este caso, tengo una lista de elementos (IItem) que se resuelven y deseo crear un repositorio para todos los elementos de ese tipo.

 var items = container.Resolve<IEnumerable<IItem<string>>>(); 
     foreach (var item in items) 
     { 
      var repository = container.Resolve(typeof (IRepository<DataItemBase>), new TypedParameter(item.GetType(), item)); 
      Assert.IsNotNull(repository); 
     } 

Gracias por su publicación que ayudó y espero que esta actualización ayude.

Cuestiones relacionadas