我试图设置一个似乎有复杂需求的Autofac模块。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
)的实现。因此,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送我在正确的方向。
作为我的问题的一部分,我忘了提及我还需要注册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<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();
}
}
相关:http://stackoverflow.com/questions/18000522/register-autofac-decorator-for-only-one-generic-command-handler – Steven
关闭:)我正在使用开放的通用接口。在那个例子中,装饰器是由特定类型决定的。我的场景由一个属性决定。我不会移动到SimpleInjector(不是我的决定):P – Mike
(我永远不能让代码指示器在WYSIWYG编辑器中工作!) – Mike