如何将此代码转换为异步等待?

nak*_*iya 5 c# task-parallel-library async-await

我有很多像这样的代码:

        var feed = new DataFeed(host, port);
        feed.OnConnected += (conn) =>
        {
            feed.BeginLogin(user, pass);
        };
        feed.OnReady += (f) =>
        {
             //Now I'm ready to do stuff.
        };

        feed.BeginConnect();
Run Code Online (Sandbox Code Playgroud)

如您所见,我使用通常的异步操作方式.如何更改此代码才能使用async await?最好是这样的:

public async void InitConnection()
{
    await feed.BeginConnect();
    await feed.BeginLogin(user, pass);

    //Now I'm ready
}
Run Code Online (Sandbox Code Playgroud)

Ser*_*kiy 10

您可以使用TaskCompletionSource<T>将EAP(基于事件的异步模式)包装到Tasks中.目前尚不清楚如何处理DataFeed类中的错误和取消操作,因此您需要修改此代码并添加错误处理(示例):

private Task ConnectAsync(DataFeed feed)
{
    var tcs = new TaskCompletionSource<object>();
    feed.OnConnected += _ => tcs.TrySetResult(null);
    feed.BeginConnect();
    return tcs.Task;
}

private Task LoginAsync(DataFeed feed, string user, string password)
{
    var tcs = new TaskCompletionSource<object>();
    feed.OnReady += _ => tcs.TrySetResult(null);
    feed.BeginLogin(user, pass);
    return tcs.Task;
}
Run Code Online (Sandbox Code Playgroud)

现在您可以使用以下方法:

public async void InitConnection()
{
    var feed = new DataFeed(host, port);
    await ConnectAsync(feed);
    await LoadAsync(feed, user, pass);
    //Now I'm ready
}
Run Code Online (Sandbox Code Playgroud)

注意 - 您可以将这些异步方法移动到DataFeed类.但是,如果您可以修改DataFeed,那么最好使用APM API TaskFactory.FromAsync包装到Tasks.

不幸的是,没有非泛型TaskCompletionSource会返回非泛型,Task所以通常解决方法是使用Task<object>.

  • +1,这就是`TaskCompletetionSource <T>`的用途.一个问题,失败后会发生什么?出于兴趣,使用`TaskCompletetionSource <object>`与`TaskCompletetionSource <bool>`有什么好处,我怀疑它没有区别? (2认同)
  • 你可以让这些方法返回`Task`,因为`Task <T>`继承自`Task`. (2认同)