2014-05-02 58 views
7

.NET中有很多類使用舊的Asynchronous Programming Model (APM),其中「不再推薦用於新開發」。 APM使用開始/結束方法對,End方法將IAsyncResult對象作爲參數。其中一類是TcpClient,使用它可以異步連接,像這樣:從異步編程模型(APM)轉移到基於任務的異步模式(TAP)

private void SomeMethod() 
{ 
    this.tcpClient = new TcpClient(); 
    IAsyncResult result = this.tcpClient.BeginConnect(ip, port, EndConnect, null); 
} 

private void EndConnect(IAsyncResult asyncResult) 
{ 
    this.tcpClient.EndConnect(asyncResult); 

    // ... do stuff ... 
} 

Task-based Asynchronous Pattern (TAP)是通過使用asyncawait關鍵字的促進異步編程的更現代的形式。

所以,如果你有一個像TcpClient的一類,它採用APM模型和不公開任何的任務,如何將一個去適應它的異步方法的TAP,使他們能夠與async/await使用嗎?

回答

11

這是in the documentation you linked to

作爲一般規則,您應該先查看或詢問直接支持TAP的更新API。幾乎所有BCL類都已經更新以支持TAP,並且少數(例如HttpWebRequest)已被替換爲TAP替代(例如HttpClient)。在這種情況下,沒有TAP TcpClient的等價物,所以包裝它們是你最好的選擇。

如果你寫了APM包裝TAP,我建議使用簡單的擴展方法:

public static Task ConnectTaskAsync(this TcpClient client, IPAddress address, int port) 
{ 
    return Task.Factory.FromAsync(client.BeginConnect, client.EndConnect, address, port, null); 
} 

這給你一個自然的方式來消耗他們,並從包含實際的邏輯的任何代碼分開你「互操作」的代碼:

async Task SomeMethodAsync() 
{ 
    this.tcpClient = new TcpClient(); 
    await this.tcpClient.ConnectTaskAsync(ip, port); 
    // ... do stuff ... 
} 
3

您可以使用Task.Factory.FromAsync。示例(對於BeginReceive/EndReceive):

public static class SocketsExt 
{ 
    static public Task ReceiveDataAsync(
     this TcpClient tcpClient, 
     byte[] buffer) 
    { 
     return Task.Factory.FromAsync(
      (asyncCallback, state) => 
       tcpClient.Client.BeginReceive(buffer, 0, buffer.Length, 
        SocketFlags.None, asyncCallback, state), 
      (asyncResult) => 
       tcpClient.Client.EndReceive(asyncResult), 
      null); 
    } 
}