Настройка Unity для разрешения типа, который принимает декорированную зависимость с параметром, который зависит от типа, в который он внедряется

Это довольно простой сценарий шаблона декоратора с той сложностью, что декорированный тип имеет параметр конструктора, который зависит от типа, в который он внедряется.

У меня есть такой интерфейс:

interface IThing
{
    void Do();
}

И такая реализация:

class RealThing : IThing
{
    public RealThing(string configuration)
    {
        ... implementation ...
    }

    public void Do()
    {
        ... implementation ...
    }
}

И такой декоратор:

class DecoratingThing : IThing
{
    IThing _innerThing;

    public DecoratingThing(IThing thing)
    {
        _innerThing = thing;    
    }

    public void Do()
    {
        _innerThing.Do();
    }
}

Наконец, у меня есть несколько типов, для которых требуется IThing , называемый Depender1 , Depender2 и т. Д.

class DependerX()
{
    public DependerX(IThing thing)
    {
        ... implementation ...
    }
}

Я хочу настроить контейнер IOC для разрешения экземпляров DependerX таким образом, чтобы в них вводился RealThing , украшенный DecoratingThing . Важно: Каждый DependerX тип требует передачи в конструктор его RealThing разных значений конфигурации , например: " ConfigX "в каждом конкретном случае. например Контейнер IoC может выполнять следующие действия:

new Depender1(new DecoratingThing(new RealThing("Config1")));
new Depender2(new DecoratingThing(new RealThing("Config2")));

... и так далее.

В Unity это кажется довольно неуклюжим для настройки, поскольку мне приходится смешивать декоратор с декорированным:

container.RegisterType<IThing, DecoratingThing>("ConfigX",
    new InjectionFactory(container => new DecoratingThing(new RealThing("ConfigX"));

container.RegisterType<DependerX>(
    new InjectionConstructor(new ResolvedParameter<IThing>("ConfigX");

И повторяю, аккуратно нарушая DRY для каждого DependerX .

Я бы хотел избавиться от необходимости встраивать конструкцию RealThing в конструкцию DecoratingThing в каждую именованную регистрацию IThing - и заявить украшение всего один раз. Это так, например, что если в будущем нужно изменить украшение, его легче перенастроить. Лучшее, что я придумал, - это вспомогательный метод регистрации:

void RegisterDepender<TDepender>(IUnityContainer container, string config)
{
    container.RegisterType<TDepender>(new InjectionConstructor(
        new ResolvedParameter<IThing>(config)));
    container.RegisterType<IThing, DecoratingThing>(config,
        new InjectionFactory(c => new DecoratingThing(new RealThing(config))));
}

По крайней мере, он удаляет повторение, но мне все равно нужно встроить конструкцию RealThing в DecoratingThing - это означает, например, что я не могу изменять их продолжительность жизни независимо друг от друга. Я не могу зарегистрировать IThing снова, чтобы сделать это, потому что я израсходовал свою регистрацию этого интерфейса для имени.Если я хочу это сделать, мне нужно ввести еще один набор именованных экземпляров, например:

void RegisterDepender<TDepender>(IUnityContainer container, string config)
{
    string realConfig = "Real" + config;

    container.RegisterType<TDepender>(new InjectionConstructor(
        new ResolvedParameter<IThing>(config)));
    container.RegisterType<IThing, DecoratingThing>(config,
        new InjectionFactory(c => new DecoratingThing(
            container.Resolve<IThing>(realConfig))));
    container.RegisterType<IThing, RealThing>(realConfig,
        new ContainerControlledLifetimeManager(),
        new InjectionConstructor(config));
}

Это действительно лучший вариант? Это сложно и потенциально трудно для тех, кто придет после грока. Есть ли у других контейнеров IoC убедительный способ охватить этот сценарий? Поскольку шаблон того, как работает внедрение, повторяется для каждого DependerX, есть ли способ использовать только именованный экземпляр на верхнем ( DependerX ) уровне?

Любые другие комментарии?

12
задан James World 25 January 2012 в 14:34
поделиться