views:

39

answers:

1

I have a method that returns a task like:

public static 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);
}

I would like to keep a reference to the task and run it later. However it seems like the task created by the FromAsync method is executed immediatly. How can I defer it's execution?

+1  A: 

For starters, if you look at the syntax, you'll realize that you're actually invoking the BeginSend method yourself and causing it to return the IAsyncResult for the first parameter of FromAsync. That's just one of the overloads of FromAsync though. If you look there's other overloads and the ones you're looking for are the ones that take Func<...> instead. Unfortunately these overloads will also invoke the method right away on your behalf due to the fact that, under the covers, what's really happening is that FromAsync is just wrapping the APM invocation pattern using a TaskCompletionSource<TResult>.

The only way I can actually see you being able to defer the execution is to actually wrap the FromAsync work up in a parent task which you don't Start yourself. For example:

public static 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 new Task<int>(() =>
    {
        return Task.Factory.FromAsync<int>(
                         socket.BeginSend(buffer, offset, count, SocketFlags.None, null, socket),
                         socket.EndSend).Result;
    }
}

Now a caller can get the task like so:

Task<int> task = SendAsync(...);

and until they call task.Start() the work would not begin.

Drew Marsh