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

您可以为您的对象定义一个接口,并使用它来代替object

public interface IChunk
{
    // whatever
}

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

然后您可以传递任何带有签名的方法,例如:

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

哪里RealChunk是一个实现IChunk. 这是可能的,这要归功于 C# 4 变体特性

于 2013-03-04T12:06:41.130 回答
1

你的课是一个好的开始。您可以通过用泛型和委托替换继承来使其更轻量级。

  1. 您更改TTChunk(更准确的命名)
  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>()引入 lambda,我们节省了一个泛型类型参数并使我们的辅助方法更轻量级。这是一个权衡,也可以通过其他方式完成。

于 2013-03-04T12:19:44.500 回答