如何让代码等待执行,直到其他事件处理程序完成?

时间:2012-01-31 17:13:44

标签: c#

在下面的代码中,我想使用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){  }

3 个答案:

答案 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而不是这可能是唯一的选择。