同步方法中的异步调用

iLe*_*ing 6 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();
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

if (CoockinRequest()) MessageBox.Show('Yay, smells even better');
Run Code Online (Sandbox Code Playgroud)

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

它可能在不同的环境中也有所不同,例如某些方法对WPF应用程序有用,有些对于其他东西以及诸如此类的东西,但应该有一般模式不对吗?

你是怎么做那些家伙的?

Ree*_*sey 7

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

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

为此,您将重写上面的代码,如下所示:

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;
}
Run Code Online (Sandbox Code Playgroud)

然后,当你去使用它时,你会写下这样的东西:

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());
}
Run Code Online (Sandbox Code Playgroud)

  • +1.Reed解决方案的另一个优点是它"等待就绪" - 在VS2011中你可以改变`SomeMethod`来使用`bool result = await CoockinRequestAsync();`和`CoockinRequestAsync`不需要改变所有. (2认同)