複雑な要件があると思われる 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 のすべての実装は、MyDecorator で[MyAttribute]
装飾されます。
私は近くにいますが、葉巻はまだありません:
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<,> のすべての実装も登録する必要があることを忘れていました。
これを2段階で行いました。最初にデコレーターに型を登録してから、残りを登録します。
私の解決策: リファクタリングが必要なのはわかっていますが、概念実証としてです。できます。
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();
}
}