在下面的代码中,我想使用geometryService
(第三方提供的实用程序类)来顺序计算多个形状区域。我失败了,因为第二次区域计算必须等到第一次计算结束。要解决此问题,我可以将第二个区域计算放入完成计算事件处理程序,但代码很乱。有没有更好的方法让geometryService.AreasAndLengthsAsync(secondShape)
等待执行直到geometryService.AreasAndLengthsAsync(firstShape)
执行完毕?
Shape firstShape = new Shape();
Shape secondShape = new Shape();
GeometryService geometryService = new GeometryService();
geometryService.AreaAndLengthsCompleted += GeometryService_AreasAndLengthsCompleted;
geometryService.AreasAndLengthsAsync(firstShape);
geometryService.AreasAndLengthsAsync(secondShape);
private void GeometryService_AreasAndLengthsCompleted(object sender, AreasAndLengthsEventArgs args){ }
答案 0 :(得分:6)
您可以将每个Shape
放入Queue<Shape>
然后启动第一个计算,并在完成的处理程序中检查队列中是否有其他形状,如果有,则处理它。
此外,您呼叫的方法是AreasAndLengthsAsync()
。通过转换,大多数API设计人员将包含名为相同的同步备选方案,而不包含异步部分。所以请寻找AreasAndLengths()
作为替代方案。
答案 1 :(得分:2)
这是异步方法的经典问题。如果你正在使用新的MS Async CTP,你可以相当干净地封装一些这些东西,但如果你使用传统的东西,很难从中获得干净的代码。
我采用的方法之一是使用延续传递模式包装事件处理程序模式。它不是很干净,但我更喜欢结果代码的外观。所以你可以这样做:
public static void GetAreasAndLengthsAsync(Shape shape, Action<SomeResult> callback)
{
var geometryService = new GeometryService();
geometryService.AreasAndLengthsCompleted += (s, e) =>
{
if (callback != null)
{
callback(e.SomeResult);
}
};
geometryService.AreasAndLengthsAsync(shape);
}
然后你可以像这样使用它:
GetAreasAndLengthsAsync(firstShape, firstShapeResult =>
{
GetAreasAndLengthsAsync(secondShape, secondShapeResult =>
{
DoSomethingWithTheseResults(firstShapeResult, secondShapeResult);
});
});
无论如何都是这样的。格式化有点难看,但至少它表达了你的意图。 (没有编译代码,可能会有错误。)
如果您不想每次都重新创建geometryService,可以在类中的字段级别执行此操作,然后将回调方法作为大多数异步方法包含的UserState参数的一部分传递。
答案 2 :(得分:1)
您可以使用AutoResetEvent或ManualResetEvent,只需在类的顶部定义一个,并在您要等待另一个事件的情况下调用Wait,然后在您等待的情况下调用Set,等待将阻塞,直到调用Set。
http://msdn.microsoft.com/en-us/library/system.threading.autoresetevent.aspx http://msdn.microsoft.com/en-us/library/system.threading.manualresetevent.aspx
我想补充一点,这不是理想的,但你必须拥有序列化事件,并且你依赖于第三方API而不是这可能是唯一的选择。