【问题标题】:Block code and wait for event handler to fire?阻止代码并等待事件处理程序触发?
【发布时间】:2012-10-15 17:07:49
【问题描述】:

我正在编写一个使用 3rd 方库来处理一些数据的应用程序。在一个非常简化的示例中,我有一个方法作为这样的任务运行:

private void ProcessListOfItems(List<string> items)
{ 
    while (items.Count > 0)
    {
        3rdPartyLibObject.Process(items[0]);
        items.Remove(0);
    }
}

如您所见,按照我当前编写代码的方式,我会在 Process() 方法返回后立即从列表中删除每个项目。但是一个项目的处理可能会失败,我需要知道是否会发生这种情况。不幸的是,Process() 方法不会返回一个 bool 值来指示该项目是否已成功处理,而是会触发 ProcessingComplete 和 ProcessingFailed 事件。我有事件处理程序连接到这样的事件:

3rdPartyLibObject.ProcessingComplete += obj_ProcessingSuccess;
3rdPartyLibObject.ProcessingFailed += obj_ProcessingFailed;

private void obj_ProcessingSuccess(object sender, 3rdPartyLibObject.ProcessingEventArgs e)
{
    this.Invoke(new ProcessedHandler(OnProcessed), new object[] { true });
}

private void obj_ProcessingFailed(object sender, 3rdPartyLibObject.ProcessingEventArgs e)
{
    this.Invoke(new ProcessedHandler(OnProcessed), new object[] { false });
}

private void OnProcessed(bool success)
{
    if (success)
    {
        Debug.WriteLine("Item was processed succesfully!");
    }
    else
    {
        Debug.WriteLine("Failed to process item!");
    }
}

我想做的是在调用 3rdPartyLibObject.Process() 之后立即设置我的代码块,直到其中一个事件处理程序触发,以便我知道该项目是否无法处理(以及我是否应该删除它是否来自列表)。我猜这可能并不少见,但我以前从未遇到过。处理这种情况是否存在普遍认可的最佳实践?

【问题讨论】:

  • 为什么不将您的项目删除代码添加到 OnProcessed 方法中?显然,这需要跟踪当前正在处理的项目,但这是我能看到的最简单的解决方案。
  • 没有什么是您班级中的 bool 字段无法解决的问题。

标签: c# .net events event-handling blocking


【解决方案1】:

就我个人而言,我会将其包装成Task&lt;bool&gt;,如下所示:

Task<bool> Process3rdParty(ThirdPartyLibObject thirdParty, string item)
{
    var tcs = new TaskCompletionSource<bool>();

    thirdParty.ProcessingComplete += (o, e) => tcs.SetResult(true);
    thirdParty.ProcessingFailed += (o, e) => tcs.SetResult(false);

    thirdParty.Process(item);

    return tcs.Task;
}

你可以这样称呼它:

private void ProcessListOfItems(List<string> items)
{ 
    while (items.Count > 0)
    {
        var task = Process3rdParty(thirdPartyLibObject.Process(items[0]);
        if (task.Result)
            items.Remove(0);
    }
}

如果您稍后决定希望它异步运行或一次处理多个项目(如果第三方库支持),这也会简化事情。这也很容易转移到 C# 5 的 async/await 支持以使整个事情异步。

【讨论】:

  • 您不想使用TrySetResult 而不是SetResult,因为两者之一会失败。
  • @Servy 如果只有一个会被调用(这是 OP 建议的),那么 SetResult 应该没问题。如果这两个事件可以在同一个实例上发生,那么TrySetResult 会更好。
  • @ReedCopsey 如何将此模式重构为 C#5 的异步/等待?
【解决方案2】:

这行得通吗:

private bool itemProcessed = false;

private void ProcessListOfItems(List<string> items)
{ 
    while (items.Count > 0)
    {
        3rdPartyLibObject.Process(items[0]);
        if (itemProcessed)
        {
            items.Remove(0);
        }
    }
}

private void obj_ProcessingSuccess(object sender,    3rdPartyLibObject.ProcessingEventArgs e)
{
    this.itemProcessed = true;
}

private void obj_ProcessingFailed(object sender, 3rdPartyLibObject.ProcessingEventArgs e)
{
    this.itemProcessed = false;
}

假设事件都在同一个线程上触发,则应在处理下一个项目之前调用处理程序。

【讨论】:

  • 感谢您的建议!虽然我最终选择了另一个答案来回答我的问题,但我很感激你的想法和你提出建议所花费的时间!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多