我試圖設置一個似乎有複雜需求的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