2009-10-06 9 views
6

La documentación indica que Autofac apoya genéricos abiertos y yo soy capaz de registrar y resolver en un caso básico de este modo:Autofac con Open Genéricos y tipo especificado en tiempo de ejecución

Registro:

builder.RegisterGeneric(typeof(PassThroughFlattener<>)) 
     .As(typeof(IFlattener<>)) 
     .ContainerScoped(); 

Resolve:

var flattener = _container.Resolve<IFlattener<Address>>(); 

El código anterior funciona bien. Sin embargo, en el supuesto que no voy a saber el tipo proporcionado a IFlattener hasta el tiempo de ejecución, lo que quiero hacer algo como esto:

object input = new Address(); 
var flattener = (IFlattener)_container.Resolve(typeof(IFlattener<>), new TypedParameter(typeof(IFlattener<>), input.GetType())); 

¿Es esto posible con autofac? Tengo la idea de la siguiente usando StructureMap:

http://structuremap.sourceforge.net/Generics.htm

que estoy tratando de lograr el mismo objetivo descrito en este artículo.

Respuesta

9

Esto es ciertamente posible con Autofac. En "registrar el tiempo", esto es lo que básicamente hace:

  1. registrar el tipo abierto genérica (PassThroughFlattener <>)
  2. registrar cualquier tipo específico (AddressFlattener)
  3. El registro de un método que puede ser usado para resolver un IFlattener basado en un objeto de entrada

en "tiempo de resolver", que va a hacer:

  1. Resolver el método
  2. Llame al método con el parámetro de entrada (s) para resolver la aplicación IFlattener

Aquí hay una (esperemos) de la muestra de trabajo:

var openType = typeof(IFlattener<>); 

var builder = new ContainerBuilder(); 
builder.RegisterGeneric(typeof(PassThroughFlattener<>)).As(openType); 
builder.Register<AddressFlattener>().As<IFlattener<Address>>(); 
builder.Register<Func<object, IFlattener>>(context => theObject => 
    { 
     var concreteType = 
      openType.MakeGenericType(theObject.GetType()); 
      return (IFlattener) context.Resolve(concreteType, 
       new PositionalParameter(0, theObject)); 
    }); 
var c = builder.Build(); 

var factory = c.Resolve<Func<object, IFlattener>>(); 

var address = new Address(); 
var addressService = factory(address); 

Assert.That(addressService, Is.InstanceOfType(typeof(AddressFlattener))); 

var anything = "any other data"; 
var anyService = factory(anything); 

Assert.That(anyService, Is.InstanceOfType(typeof(PassThroughFlattener<string>))); 
+0

Gracias por la respuesta rápida, ¡eso funciona! –

4

Si no saben tipo hasta tiempo de ejecución puede construirlo usando MakeGenericType:

var addressFlattener = _container.Resolve(typeof(IFlattener<>).MakeGenericType(typeof(Address))); 
Cuestiones relacionadas