Why does an overload of TaskFactory.FromAsync () require a state object to be provided?

As detailed in TPL and traditional asynchronous programming of the .NET Framework . MSDN and Stephen Toub article. Tasks and APM template . TaskFactory.FromAsync() and TaskFactory<TResult>.FromAsync() can be used to adapt Begin * () and End * APIs () that match the APM pattern for use with the parallel task library.

Below I will consider only TaskFactory<TResult>.FromAsync() overloads, since my question does not depend on whether the API compatible APIs value.

There are three overloads that accept an IAsyncResult object, namely:

  • FromAsync(IAsyncResult, Func<IAsyncResult, TResult>)
  • FromAsync(IAsyncResult, Func<IAsyncResult, TResult>, TaskCreationOptions)
  • FromAsync(IAsyncResult, Func<IAsyncResult, TResult>, TaskCreationOptions, TaskScheduler)

I understand that these APIs are useful in scenarios where the Begin * () API method contains more than three parameters in addition to AsyncCallback and the object state (for example, Too many arguments in BeginXXX for FromAsync ? ), Or when the Begin*() API is not completely matches the APM pattern because it does not accept the object state parameter (for example, How to use AsyncCTP using the APM TFS method ( Query.Begin / EndQuery )? ).

I do not understand why other overloads (for example, FromAsync(Func<AsyncCallback, Object, IAsyncResult>, Func<IAsyncResult, TResult>, Object) ) require the provision of the state object . This object state is passed to the Begin*() API, but in the APM template, the object state is intended for private use by the caller. Thus, it doesn't matter what state the object passes to the Begin*() API on FromAsync() .

The MSDN article above has a section called โ€œProviding User State Dataโ€ that recommends capturing any required state in a continuation deletion and passing null for the FromAsync() state object. However, this does not explain why FromAsync() methods require the provision of a state object.

Why is it necessary to pass an object state if it is not available to the returned Task<TResult> ?

+4
source share
1 answer

Well, if you follow the source code , you can see that the state can indeed be obtained from the Task instance using (not so surprisingly named) Task.AsyncState :

 var task = Task.Factory.FromAsync<TResult>(...); object state = task.AsyncState 

This property also contains the status of the asynchronous operation in other scripts, such as Task.Factory.StartNew :

 var task = Task.Factory.StartNew(_ => { }, "bar"); Console.WriteLine(task.AsyncState); // prints "bar" 

So, since the state is available, it is expected that it will be able to pass the state as a parameter and double the API once with the state parameter and once without it will not look like the best option. Especially when you can just pass null .

+4
source

All Articles