1

私たちのコードベースには、基本的に単なる配管であり、次のような多くのメソッドがあります。

    public void Execute()
    {
        _performanceLogger.Log("Start");

        var chunks = GetChunksToWorkOn();

        Parallel.ForEach(chunks , chunk =>
        {
            using (var container = ObjectFactory.Container.GetNestedContainer())
            {
                using (var unitOfWork = new UnitOfWork())
                {
                    container.GetInstance<Worker>().Execute(chunk);
                    unitOfWork.Commit();
                }
            }
        });

        _performanceLogger.Log("Done");
    }

これらの呼び出しを置き換えるテンプレート メソッドを作成することを考えていました。

public interface IProcessInParallel
{
    void Execute<T>(Func<IEnumerable<IEnumerable<object>>> funcToRetrieveChunksOfWorkForEachParallelProcess) where T : IProcessInParallelTask;
}

public interface IProcessInParallelTask
{
    void DoWork(IEnumerable<object> objects);
}

public class ProcessInParallel : IProcessInParallel
{
    private readonly IPerformanceLogger _performanceLogger;

    public ProcessInParallel(IPerformanceLogger performanceLogger)
    {
        _performanceLogger = performanceLogger;
    }

    public void Execute<T>(Func<IEnumerable<IEnumerable<object>>> funcToRetrieveChunksOfWorkForEachParallelProcess) where T : IProcessInParallelTask
    {
        _performanceLogger.Log("Start");

        var chunks = funcToRetrieveChunksOfWorkForEachParallelProcess.Invoke();

        Parallel.ForEach(chunks, chunk =>
        {
            using (var container = ObjectFactory.Container.GetNestedContainer())
            {
                using (var unitOfWork = new UnitOfWork())
                {
                    container.GetInstance<T>().DoWork(chunk);
                    unitOfWork.Commit();
                }
            }
        });

        _performanceLogger.Log("Done");
    }
}

このアプローチの唯一の問題は、それがオブジェクトを使用していることです...これは醜くて安全ではなく、キャストを引き起こします。

私は自分のパターンブックを閲覧していますが、まだ正しい解決策を見つけていません.

助言がありますか?

4

2 に答える 2

1

あなたのクラスは良いスタートです。継承をジェネリックとデリゲートに置き換えることで、これをより軽量にすることができます。

  1. あなたは(より正確な命名)に変更TしますTChunk
  2. チャンク ファクトリは次のタイプである必要がありますFunc<TChunk>
  3. そして、チャンクで実行された作業を表すデリゲートが必要です。Action<IContainer, container>
public void Execute<TChunk>(var _performanceLogger, Func<TChunk> getChunks, Action<IContainer, container> doWork)
    {
        _performanceLogger.Log("Start");

        var chunks = getChunks();

        Parallel.ForEach(chunks, chunk =>
        {
            using (var container = ObjectFactory.Container.GetNestedContainer())
            {
                using (var unitOfWork = new UnitOfWork())
                {
                    doWork(container, chunk);
                    unitOfWork.Commit();
                }
            }
        });

        _performanceLogger.Log("Done");
    }
}


Execute<IEnumerable<object>>(
    logger,
    () => GetChunksToWorkOn(),
    (container, chunk) => container.GetInstance<Worker>().DoWork(chunk));

これに対するバリエーションは確かに可能です。継承に依存していないことに注意してください。とにかく、インターフェースは論理的には機能パックにすぎません。

ラムダにプルcontainer.GetInstance<Worker>()することで、ジェネリック型パラメーターを 1 つ節約し、ヘルパー メソッドをより軽量にします。これは、他の方法でも実行できるトレードオフです。

于 2013-03-04T12:19:44.500 に答える
1

チャンクオブジェクトのインターフェイスを定義して、代わりに使用できますobject

public interface IChunk
{
    // whatever
}

public interface IProcessInParallel
{
    void Execute<T>(Func<IEnumerable<IEnumerable<IChunk>>> getChunks) where T : IProcessInParallelTask;
}

次に、次のような署名付きのメソッドを渡すことができます。

IEnumerable<IEnumerable<RealChunk>> GetRealChunks()
{
    //...
}

whereRealChunkは を実装するクラスですIChunk。これは、C# 4 バリアンス機能のおかげで可能です。

于 2013-03-04T12:06:41.130 に答える