Pregunta

La documentación indica que Autofac apoya genéricos abiertos y yo soy capaz de registrar y resolver en un caso básico de esta manera:

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

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

¿Fue útil?

Solución

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

  1. Registrar el tipo genérico abierto (PassThroughFlattener <>)
  2. registrar ningún tipo específico (AddressFlattener)
  3. El registro de un método que se puede utilizar para resolver un IFlattener basado en un objeto de entrada

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

  1. Resolver el método
  2. llama al método con el parámetro (s) de entrada 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>)));

Otros consejos

Si usted no sabe el tipo hasta el tiempo de ejecución se puede construir utilizando MakeGenericType:

var addressFlattener = _container.Resolve(typeof(IFlattener<>).MakeGenericType(typeof(Address)));
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top