4

こんにちは、私はすべてのプロジェクトでSimple Injector DI コンテナーを使用し始めています。私の要件に強力な機能を適合させる方法についてアドバイスをお願いします。

コマンドをラップするコマンドハンドラーデコレーターがいくつかあります。

public class TransactionCommandHandlerDecorator<TCommand>
    : ICommandHandler<TCommand>
{
    private readonly ICommandHandler<TCommand> handlerToCall;
    private readonly IUnitOfWork unitOfWork;

    public TransactionCommandHandlerDecorator(
        IUnitOfWork unitOfWork, 
        ICommandHandler<TCommand> decorated)
    {
        this.handlerToCall = decorated;
        this.unitOfWork = unitOfWork;
    }

    public void Handle(TCommand command)
    {
         this.handlerToCall.Handle(command);
         unitOfWork.Save();
    }
}

Mutex デコレータ:

public class TransactionCommandHandlerWithMutexDecorator<TCommand>
    : ICommandHandler<TCommand>
{
    private readonly ICommandHandler<TCommand> handlerToCall;
    private readonly IUnitOfWork unitOfWork;
    private static object Lock = new object();

    public TransactionCommandHandlerWithMutexDecorator(
        IUnitOfWork unitOfWork, 
        ICommandHandler<TCommand> decorated)
    {
        this.handlerToCall = decorated;
        this.unitOfWork = unitOfWork;
    }

    public void Handle(TCommand command)
    {
        lock (Lock)
        {
            this.handlerToCall.Handle(command);
            unitOfWork.Save();
        }
    }
}

場合によっては、一部のコマンドをこのブロック方法 (TransactionCommandHandlerWithMutexDecorator を使用) でラップし、他のコマンドをすべてのスレッドで自由にアクセスできるようにする (TransactionCommandHandlerDecorator を使用) だけが理にかなっています。私の現在のコードでは、ロックは静的であり、すべてのタイプ間で共有されます。

だから私の質問に:

1) 特定のコマンドに TransactionCommandHandlerWithMutexDecorator を適用し、残りのコマンドに TransactionCommandHandlerDecorator を使用するにはどうすればよいですか? ExpressionBuilt イベントを使用しますか?

2)装飾したいコマンドごとに新しいクラスを作成する必要がありますか(コマンドごとに一意のロックオブジェクトがあることを確認するため)、または(傍受を使用して)より良い方法がありますか?

上記を行うための最良の方法についてアドバイスをいただければ幸いです。

ありがとう、

クリス

4

1 に答える 1

8

私の現在のコードでは、ロックは静的であり、すべてのタイプ間で共有されます。

これは正しくありません。ジェネリック型は static members を共有しません。ごとTCommandに新しい静的タイプがあります。言い換えれば、a Decorator<int>will は a will とは異なるstatic object LockインスタンスDecorator<string>を持ちます。

逆に、すべてのコマンドに対して単一のロックを使用する場合、これは少し難しくなります。基本的に次の 3 つのことを行うことができます。

  1. 非ジェネリック ベースからデコレータを派生させ、そこでロックを定義します。
  2. 静的な非ジェネリック クラスでロックを定義し、ジェネリック デコレータ内からそのクラスを参照します。
  3. ロックを非ジェネリック クラスに移動し、これを通常の依存関係としてデコレーターに注入します。

しかし、繰り返しますが、これはあなたが望むものではありません。必要な動作はデフォルトで発生するものであり、これは Simple Injector とは関係ありません。これが、ジェネリックが C# と .NET で機能する方法です。

TransactionCommandHandlerWithMutexDecorator を特定のコマンドまたはコマンドに適用し、残りのコマンドに TransactionCommandHandlerDecorator を使用するにはどうすればよいですか

これは思ったより簡単です。RegisterDecoratorを受け取るオーバーロードがあり、Predicate<T>いつ装飾するかを伝えることができます。これは次のようになります。

// Some helper methods
private static Type GetCommandType(Type handlerType)
{
    return handlerType.GetGenericArguments()[0];
}

private static bool IsMutexCommand(Type commandType)
{
    // Determine here is a class is a mutex command. 
    // Example:
    return typeof(IMutexCommand).IsAssignableFrom(commandType);
}

// Decorator registration with predicates.
container.RegisterDecorator(
    typeof(ICommandHandler<>),
    typeof(TransactionCommandHandlerWithMutexDecorator<>),
    c => IsMutexCommand(GetCommandType(c.ServiceType)));

// Decorator registration with predicates.
container.RegisterDecorator(
    typeof(ICommandHandler<>),
    typeof(TransactionCommandHandlerDecorator<>),
    c => !IsMutexCommand(GetCommandType(c.ServiceType)));

Simple Injector のすべてと同様に、RegisterDecorator高度に最適化されています。通常の状況* では、述語は 1 回だけ呼び出されます。

*複数のスレッドが同時に同じインスタンスを同時に要求している場合、述語が複数回呼び出される可能性がありますが、構築された式がキャッシュされ、デリゲートが構築された後、述語は呼び出されなくなります。

于 2012-06-14T21:02:56.030 に答える