2

私は2つのデコレータを持っています:

class DbCommandWithTransactionHandlerDecorator<TCommand>
    : IDbCommandHandler<TCommand> { ... }

class DbOptimisticConcurrencyRetryDecorator<TCommand>
    : IDbCommandHandler<TCommand> { ... }

これらのデコレータは、トランザクション管理と楽観的同時実行再試行機能をデータベースコマンドに追加します。

IoCコンテナとしてAutofacを使用しています。AutofacをセットアップIDbCommandHandler<>して、アセンブリ内にあるすべてのものを自動配線します。たとえば、を要求すると、最初に、、次に。IDbCommandHandler<CreateNewNotificationCommand>で自動的に装飾されます。DbCommandWithTransactionHandlerDecoratorDbOptimisticConcurrencyRetryDecorator

Autofacでこれを取得しようとしていますbuilder.RegisterGenericDecorator()が、まだ管理していません。主な問題は、デコレータが機能するために「名前付き」引数が必要なことです。以下は、私が達成したいものに最も「近い」サンプルコードです-しかし、主な欠陥は、私がまだタイプを手動で登録しなければならなかったことです。

var builder = new ContainerBuilder();
var a = Assembly.GetExecutingAssembly();

// I need to find a way how these can be 'auto-wired', 
// rather than having to manually wire each command.

builder.RegisterType<CreateNewNotificationCommandHandler>()
    .Named<IDbCommandHandler<CreateNewNotificationCommand>>("command");
builder.RegisterType<CreateNewNotificationCommandHandler_2>()
    .Named<IDbCommandHandler<CreateNewNotificationCommand_2>>("command");

builder.RegisterGenericDecorator(
    typeof(DbCommandWithTransactionHandlerDecorator<>),
    typeof(IDbCommandHandler<>),
    fromKey: "command");

var container = builder.Build();
var handler1 =
  container.Resolve<IDbCommandHandler<CreateNewNotificationCommand>>();
var handler2 =
  container.Resolve<IDbCommandHandler<CreateNewNotificationCommand_2>>();
handler1.Handle(null); //these are correctly decorated
handler2.Handle(null); //these are correctly decorated
4

1 に答える 1

3

私はリフレクションを介して回避策を見つけることができましたが、それは実際にはエレガントではありません。完全を期すために、以下に投稿します。

 public interface IDbCommandHandler<in TCommand>: IDbCommandHandlerStub
    where TCommand : IDbCommand
{
    void Handle(TCommand command);
}

public interface IDbCommandHandlerStub
{

}

    private List<Type> getTypesThatImplementIDbCommandHandler(IEnumerable<Assembly> assemblyList)
    {
        List<Type> list = new List<Type>();
        foreach (var a in assemblyList)
        {
            var matches = a.GetTypes().Where(t => typeof(IDbCommandHandlerStub).IsAssignableFrom(t));
            list.AddRange(matches);
        }
        return list;
    }

private void registerDbCommands(List<Type> dbCommandHandlerTypes, ContainerBuilder builder)
    {
        foreach (var t in dbCommandHandlerTypes)
        {
            var interfaces = t.GetInterfaces();
            foreach (var i in interfaces)
            {
                builder.RegisterType(t).Named("dbCommand", i);
            }

        }
    }


   public void Test1()
   {
        ContainerBuilder builder = new ContainerBuilder();
        var dbCommandHandlerTypes = getTypesThatImplementIDbCommandHandler(assemblies);
        registerDbCommands(dbCommandHandlerTypes, builder);            

        builder.RegisterGenericDecorator(typeof(DbCommandWithTransactionHandlerDecorator<>),
                                        typeof(IDbCommandHandler<>),
                                        fromKey: "dbCommand", toKey:"dbCommandWithTransaction").SingleInstance();

        builder.RegisterGenericDecorator(typeof(DbOptimisticConcurrencyRetryDecorator<>),
                                        typeof(IDbCommandHandler<>),
                                        fromKey: "dbCommandWithTransaction").SingleInstance();

        var container = builder.Build();
        var handler1 = container.Resolve<IDbCommandHandler<CreateNewNotificationCommand>>();

}

まず、リフレクションを介して、を実装するすべてのタイプを取得しますIDbCommandHandler。次に、それらを実装するすべてのインターフェイスの名前付きタイプとして登録し、「dbCommand」という名前を付けます。

次に、汎用デコレータを登録して、「dbCommand」という名前の型をデコレートします。このデコレータは「dbCommandWithTransaction」という名前で、並行性の再試行のために別の汎用デコレータを登録するために使用されます。

これは一度行われることであり、「忘れられた」ことを考えると、私はこの回避策を実行する準備ができていました。しかし、私は他のIoCコンテナーを試していて、Simple Injectorに出くわしました。これはすべて、たった2行のコードで実行できます。

于 2012-10-18T15:24:10.493 に答える