簡體   English   中英

如何將此代碼轉換為異步等待?

[英]How to convert this code to 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();

如您所見,我使用通常的異步操作方式。 如何更改此代碼以使用async await 最好是這樣的:

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

    //Now I'm ready
}

您可以使用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;
}

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

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

注意 - 您可以將這些異步方法移動到DataFeed類。 但是,如果您可以修改DataFeed,那么最好使用TaskFactory.FromAsyncAPM API包裝到Tasks。

遺憾的是,沒有非泛型的TaskCompletionSource會返回非泛型Task所以通常的解決方法是使用Task<object>

您需要更改DataFeed類以支持它。 你只需要在那里使用任務異步模式。 這意味着DataFeed中的所有異步方法都必須返回一個Task (或一些Task<T> ),並且它們應該被命名為ConnectAsync (例如)。

現在,使用Socket ,這並不容易,因為Socket上的XXXAsync方法實際上並不等待! 最簡單的方法是TcpListener使用TcpClientTcpListener (假設您使用的是TCP):

public async Task<bool> LoginAsync(TcpClient client, ...)
{
  var stream = client.GetStream();

  await stream.WriteAsync(...);

  // Make sure you read all that you need, and ideally no more. This is where
  // TCP can get very tricky...
  var bytesRead = await stream.ReadAsync(buf, ...);

  return CheckTheLoginResponse(buf);
}

然后從外面使用它:

await client.ConnectAsync(...);

if (!(await LoginAsync(client, ...))) throw new UnauthorizedException(...);

// We're logged in

這只是示例代碼,我假設您實際上能夠編寫合適的TCP代碼。 如果你這樣做,使用await異步編寫它並不是很難。 只是確保你總是在等待一些異步I / O操作。

如果你想只使用Socket做同樣的事情,你可能不得不使用Task.FromAsync ,它提供了一個圍繞BeginXXX / EndXXX方法的包裝器 - 非常方便。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM