Question

The documentation states that Autofac supports open generics and I am able to register and resolve in a basic case like so:

Registration:

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

Resolve:

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

The above code works just fine. However, assuming that I will not know the type provided to IFlattener until runtime, I want to do something like this:

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

Is this possible with AutoFac? I got the idea from the following using StructureMap:

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

I'm trying to achieve the same goal outlined in this article.

Was it helpful?

Solution

This is certainly possible with Autofac. At "register time", this is what you basically do:

  1. Register the open generic type (PassThroughFlattener<>)
  2. Register any specific types (AddressFlattener)
  3. Register a method that can be used to resolve an IFlattener based on a input object

At "resolve time", you will do:

  1. Resolve the method
  2. Call the method with input parameter(s) to resolve the IFlattener implementation

Here's a (hopefully) working sample:

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>)));

OTHER TIPS

If you don't know type until runtime you can build it using MakeGenericType:

var addressFlattener = _container.Resolve(typeof(IFlattener<>).MakeGenericType(typeof(Address)));
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top