我正在尝试设置一个似乎有复杂要求的 Autofac 模块。
开始:
我有一个通用接口:
public interface IMyInterface<TFoo, TBar>
我有一堆实现这个接口的类
例如
class MyImpl1 : IMyInterface<string, bool> { }
class MyImpl2 : IMyInterface<bool, string> { }
class MyImpl3 : IMyInterface<bool, string> { }
最后,我有一个装饰器:
class MyDecorator<TFoo, TBar> : IMyInterface<TFoo, TBar>
我只想“装饰”MyInterface
具有特定属性的(的)实现。因此,所有具有 Attribute 的 MyInterface 实现[MyAttribute]
都使用 MyDecorator 进行装饰。
我很接近但还没有雪茄:
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<IMyInterface<string,bool>>());
Console.WriteLine(container.Resolve<IMyInterface<bool,bool>>());
我知道拼图的最后一块是钥匙,它实际上需要将类型传递给Keyed("CachableQueries", THE_TYPE);
但它不是在玩球。
更新
nemesv 让我朝正确的方向前进。
作为我的问题的一部分,我忘了提到我还需要注册没有 [MyAttribute] 的 IMyInterface<,> 的所有实现。
我分两个阶段做到了这一点。首先用装饰器注册类型,然后注册其余的。
我的解决方案:我知道它需要重构,但作为概念证明。有用。
class Program
{
static void Main(string[] args)
{
var builder = new ContainerBuilder();
//Get all the types we're interested in (that inherit IMyInterface)
List<Type> 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<Type, bool> 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<IMyInterface<string, bool>>());
Console.WriteLine(container.Resolve<IMyInterface<bool, bool>>());
//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();
}
}