2014-05-02 32 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); 
    } 
}