同步方法中的异步调用

时间:2011-10-20 21:00:10

标签: c# multithreading c#-4.0

以下是一个简单的例子:

public event EventHandler CookinDone = delegate{};

public void CoockinRequest(){
    var indicator = new ActivityIndicator();
    ActivityIndicator.Show("Oooo coockin' something cool");

    var bw = new BackgroundWorker();    
    bw.DoWork += (sender, e) => CockinService.Cook();
    bw.RunWorkerCompleted += (sender, e) => {
       indicator.Hide();
       CookinDone.Invoke(this,null);
    };

    bw.RunWorkerAsync();
}

现在,每次我使用该方法时,我都必须拦截CookinDone事件并继续前进。

var cook = new Cook();
cook.CookinDone += (sender, e) => MessageBox.Show("Yay, smells good");
cook.CoockinRequest();

但是如何通过将方法的返回类型设置为布尔值并在Cookin完成时返回结果来简化它?

if (CoockinRequest()) MessageBox.Show('Yay, smells even better');

如果我放在while (bw.IsBusy)之类的东西,它会拧我的ActivityIndi​​cator,冻结主线程,我觉得这将是最糟糕的事情。还有一些Monitor.Wait的东西和其他一些东西,比如TaskFactory,但所有这些东西似乎都太复杂了,无法在简单的场景中使用。

在不同的环境中它可能也有所不同,比如某些方法对WPF应用程序有用,有些对于其他东西有什么好处,但是应该有一般模式不对吗?

你是怎么做那些人的?

1 个答案:

答案 0 :(得分:7)

在.NET 4中没有直接的方法。这实际上非常符合下一版C#中新的async / await功能。

可以在.NET 4中使用任务并行库来实现此目的。您可以通过更改代码返回Task<bool>来执行此操作,以便调用者可以等待它(如果需要),或者在完成此任务时运行的任务上订阅 continuation

为此,你要重写上面的代码:

public Task<bool> CoockinRequestAsync()
{
    var indicator = new ActivityIndicator();
    ActivityIndicator.Show("Oooo coockin' something cool");

    // This assumes Cook() returns bool...
    var task = Task.Factory.StartNew(CockinService.Cook);

    // Handle your removal of the indicator here....
    task.ContinueWith( (t) => 
       {
           indicator.Hide();
       }, TaskScheduler.FromCurrentSynchronizationContext());

    // Return the task so the caller can schedule their own completions
    return task;
}

然后,当你去使用它时,你会写出类似的东西:

private void SomeMethod()
{
    var request = this.CoockinRequestAsync();

    request.ContinueWith( t =>
    {
        // This will run when the request completes... 
        bool result = t.Result;

        // Use result as needed here, ie: update your UI

    }, TaskScheduler.FromCurrentSynchronizationContext());
}