在我们的代码库中,我们有很多方法,基本上只是管道,看起来像这样:
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");
}
}
这种方法的唯一问题是它使用对象......这是丑陋不安全并导致强制转换。
我正在浏览我的模式书但尚未找到合适的解决方案。
有什么建议吗?
答案 0 :(得分:1)
您可以为 chunk 对象定义一个接口,并使用它代替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
的类。这是可能的,thanks to C# 4 variance feature。
答案 1 :(得分:1)
你的课程是一个好的开始。您可以通过使用泛型和委托替换继承来使其更轻量化。
T
更改为TChunk
(更准确的命名)Func<TChunk>
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,我们保存了一个泛型类型参数,并使我们的辅助方法更轻量级。这是一种权衡,也可以通过其他方式进行。