Autofac с открытыми обобщениями и типом, указанным во время выполнения - PullRequest
6 голосов
/ 06 октября 2009

В документации говорится, что Autofac поддерживает открытые дженерики, и я могу зарегистрироваться и разрешить в базовом случае, например:

Регистрация:

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

Resolve:

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

Приведенный выше код работает просто отлично. Однако, предполагая, что я не буду знать тип, предоставленный IFlattener до времени выполнения, я хочу сделать что-то вроде этого:

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

Возможно ли это с AutoFac? Я получил идею из следующего использования StructureMap:

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

Я пытаюсь достичь той же цели, о которой говорится в этой статье.

Ответы [ 2 ]

9 голосов
/ 06 октября 2009

Это, конечно, возможно с Autofac. В «время регистрации» это то, что вы в основном делаете:

  1. Регистрация открытого универсального типа (PassThroughFlattener <>)
  2. Регистрация любых определенных типов (AddressFlattener)
  3. Зарегистрируйте метод, который можно использовать для разрешения IFlattener на основе входного объекта

В «время разрешения» вы будете делать:

  1. Разрешить метод
  2. Вызвать метод с входными параметрами для разрешения реализации IFlattener

Вот (надеюсь) рабочий образец:

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>)));
4 голосов
/ 09 ноября 2009

Если вы не знаете type до времени выполнения, вы можете создать его, используя MakeGenericType:

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