Зарегистрируйте декоратор в autofac без указания всех зависимостей вручную
У меня есть декоратор, который имеет некоторые другие зависимости, которые также должны быть разрешены с помощью контейнера.
Пример:
public class FooDecorator : IFoo
{
public FooDecorator(IFoo inner, IBar bar, IBaz baz)
}
Я могу зарегистрировать это следующим образом:
builder.RegisterType<Foo>().As<IFoo>();
builder.RegisterDecorator<IFoo>((c, inner) =>
new FooDecorator(inner, c.Resolve<IBar>(), c.Resolve<IBaz>()), "key");
Это работает, однако не так приятно, что мне нужно вручную указать все другие зависимости. Я хотел бы сделать следующее:
builder.RegisterDecorator<FooDecorator, IFoo>("key");
Если IFoo
разрешено "внутреннее" IFoo
, а остальные зависимости разрешены из контейнера. Возможно ли это, или я могу зарегистрировать декоратор с помощью Func, который приведет к такому поведению?
Ответы
Ответ 1
Чтобы избежать указания всех зависимостей вручную, вы должны зарегистрировать декоратор в Autofac и разрешить его внутри первого параметра метода RegisterDecorator
.
builder.RegisterType<Foo>()
.Named<IFoo>("original");
builder.RegisterType<FooDecorator>()
.Named<IFoo>("decorator");
builder.RegisterDecorator<IFoo>((c, inner) => c.ResolveNamed<IFoo>("decorator", TypedParameter.From(inner)), "original")
.As<IFoo>();
Регистрация декоратора с использованием именованной регистрации позволит избежать конфликтов.
Ответ 2
На основании ответа Кирилла Дюрана, вот общий вспомогательный метод регистрации декоратора:
private void RegisterDecorator<TInterface, TImplementation, TDecorator>(ContainerBuilder builder) where TImplementation : TInterface where TDecorator : TInterface
{
builder.RegisterType<TImplementation>().Named<TInterface>("implementation");
builder.RegisterType<TDecorator>().Named<TInterface>("decorator");
builder.RegisterDecorator<TInterface>((c, inner) => c.ResolveNamed<TInterface>("decorator", TypedParameter.From(inner)), "implementation");
}
Если требуется более одного вложенного декоратора, можно ввести аналогичный метод с более универсальными параметрами (TDecorator1, TDecorator2 и т.д.).
Ответ 3
Основываясь на ответе Эзолотко, я сделал расширение.
public static void RegisterDecorator<TInterface, TImplementation, TDecorator>
(this ContainerBuilder builder)
where TImplementation : TInterface
where TDecorator : TInterface
{
var innerImplementationName = $"{typeof(TImplementation).Name} as implementation";
var decoratorName = $"{typeof(TDecorator).Name} as decorator";
builder.RegisterType<TImplementation>().Named<TInterface>(innerImplementationName);
builder.RegisterType<TDecorator>().Named<TInterface>(decoratorName);
builder.RegisterDecorator<TInterface>((c, inner) => c.ResolveNamed<TInterface>(decoratorName, TypedParameter.From(inner)), innerImplementationName);
}
}
Кретин во мне глубоко ценит то, как аккуратно мы украшаем друг друга ответы на этот вопрос о декораторах.
редактировать
Autofac v4.9 добавляет функцию RegisterDecorator. Проверьте это, это круто.