インターフェイスでタスクを返す必要がある場合は、BeginSend()呼び出しを行うためだけにスレッドプールでの作業を不必要にスケジュールすることになります(これは、FromAsync()呼び出しが別のタスクによってラップされている前の回答で起こっていることです)。
代わりに、インターフェースを変更できる場合は、次のような標準の遅延実行手法を使用できます。
public static Func<Task<int>> SendAsync(this Socket socket, byte[] buffer, int offset, int count)
{
if (socket == null) throw new ArgumentNullException("socket");
if (buffer == null) throw new ArgumentNullException("buffer");
return () =>
Task.Factory.FromAsync<int>(
socket.BeginSend(buffer, offset, count, SocketFlags.None, null, socket),
socket.EndSend);
}
呼び出し元は結果を呼び出して操作を開始し(つまり、FromAsync / BeginSendを呼び出し)、ContinueWith()を使用して結果を処理します。
Func<Task<int>> sendAsync = socket.SendAsync(buffer, offset, count);
sendAsync().ContinueWith(
antecedent => Console.WriteLine("Sent " + antecedent.Result + " bytes."));
インターフェイスでFunc<>を公開することが適切でない場合は、別のクラスにラップすることができます。
public class DelayedTask<TResult>
{
private readonly Func<Task<TResult>> func;
public DelayedTask(Func<Task<TResult>> func)
{
this.func = func;
}
public Task<TResult> Start()
{
return this.func();
}
}
public static DelayedTask<int> SendAsync(this Socket socket, byte[] buffer, int offset, int count)
{
if (socket == null) throw new ArgumentNullException("socket");
if (buffer == null) throw new ArgumentNullException("buffer");
return new DelayedTask<int>(() =>
Task.Factory.FromAsync<int>(
socket.BeginSend(buffer, offset, count, SocketFlags.None, null, socket),
socket.EndSend));
}
そして、発信者は次のようになります。
DelayedTask<int> task = socket.SendAsync(buffer, offset, count);
task.Start().ContinueWith(
antecedent => Console.WriteLine("Sent " + antecedent.Result + " bytes."));