AutoFac - регистрация декоратора для некоторых открытых Generic
Я пытаюсь установить модуль Autofac, который кажется сложным требованием.
вот оно:
У меня есть общий интерфейс:
public interface IMyInterface
У меня есть куча классов, которые реализуют этот интерфейс
например
class MyImpl1 : IMyInterface { }
class MyImpl2 : IMyInterface { }
class MyImpl3 : IMyInterface { }
Наконец, у меня есть декоратор:
class MyDecorator : IMyInterface
Я только хочуУкрасьте» реализации (изMyInterface
), которые имеют определенный атрибут. Таким образом, все реализации MyInterface, которые имеют атрибут[MyAttribute]
украшены MyDecorator.I '
м близко, но сигары еще нет:
var builder = new ContainerBuilder();
builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())
.Where(type => type.GetCustomAttributes(true)
.Any(attr => attr.GetType() == typeof(MyAttribute)))
.AsClosedTypesOf(typeof (IMyInterface))
.Keyed("CachableQueries", typeof(IMyInterface));
builder.RegisterGenericDecorator(typeof(MyDecorator),
typeof(IMyInterface), "CachableQueries");
var container = builder.Build();
Console.WriteLine(container.Resolve());
Console.WriteLine(container.Resolve());
Я понимаю, что последний кусок головоломки - это ключ, на самом деле нужно передать тип вKeyed("CachableQueries", THE_TYPE);
но это не игра в мяч.
Обновить
Немеш отправил меня в правильном направлении.
В качестве части моего вопроса я забыл упомянуть, что мне также необходимо зарегистрировать все реализации IMyInterface <,> это нене иметь [MyAttribute].
Я сделал это в два этапа. Сначала зарегистрируйте типы с помощью Decorator, а затем зарегистрируйте остальные.
Мое решение: я знаю, что это нуждается в рефакторинге, но в качестве доказательства концепции. оно работает.
class Program
{
static void Main(string[] args)
{
var builder = new ContainerBuilder();
//Get all the types we're interested in (that inherit IMyInterface)
List typesToQuery = Assembly.GetExecutingAssembly().GetTypes()
.Where(type => type.GetInterfaces()
.Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof (IMyInterface))).ToList();
//Even tho the decorator inherits IMyInterface (we don't want to process it)
typesToQuery.Remove(typeof (MyDecorator));
//build a dictionary of all the types, so we don't process them again.
Dictionary typesToProcess = typesToQuery.ToDictionary(queryType => queryType, queryType => false);
//Register all types that have [MyAttribute]
foreach (var type in typesToQuery
.Where(type => type.GetCustomAttributes(true)
.Any(attr => attr.GetType() == (typeof(MyAttribute)))))
{
builder.RegisterType(type).Keyed("CachableQueries",
type.GetInterfaces()
.First(i =>
i.IsGenericType &&
i.GetGenericTypeDefinition() == typeof(IMyInterface)));
typesToProcess[type] = true; //update, so this type isn't processed again
}
//Decorate the correct ones
builder.RegisterGenericDecorator(typeof(MyDecorator), typeof(IMyInterface), fromKey: "CachableQueries");
//Register the rest of the types we're interested
foreach (Type type in typesToProcess.Where(kvp => kvp.Value == false).Select(pair => pair.Key))
{
builder.RegisterType(type).As(
type.GetInterfaces()
.First(i =>
i.IsGenericType &&
i.GetGenericTypeDefinition() == typeof(IMyInterface)));
}
var container = builder.Build();
Console.WriteLine(container.Resolve());
Console.WriteLine(container.Resolve());
//Result:
//AutoFacPlay.MyDecorator`2[System.String,System.Boolean] - this one was decorated (as it has MyAttribute)
//AutoFacPlay.MyImplementation2 - this one wasn't decorated
Console.ReadLine();
}
}