A Tour of Task, Part 2: AsyncState and CreationOptions
• CommentsI skipped last week’s blog post (since I was working on the site redesign), so today is a 2-for-1 deal! :)
AsyncState
The AsyncState
property implements IAsyncResult.AsyncState
. This member was useful back in the day, but not so much in modern applications.
When asynchronous programming was going through its awkward teen stage, AsyncState
was an important part of the Asynchronous Programming Model (APM). The Begin*
method would take a state
parameter, which is assigned to the IAsyncResult.AsyncState
member. Later, when the application code’s callback is invoked, it could access the AsyncState
value to determine which asynchronous operation completed.
IAsyncResult.AsyncState
(and other “state”-like parameters) are no longer necessary these days; a lambda callback can easily capture any number of local variables in a type-safe way. I prefer the lambda approach; it is more expressive, less brittle, and more flexible than a single object state
parameter. However, the state
parameter approach avoids memory allocation, so it is still sometimes used in performance-sensitive code.
In modern code, the Task.AsyncState
member is mainly used for interoperation from Task
to APM. This is only necessary if you’re writing async
/await
code that must exist within an older asynchronous framework (a rare situation these days). In that scenario, you’re implementing the Begin*
/End*
methods and using a Task
instance as your implementation of IAsyncResult
. The standard approach is to create a Task<T>
using TaskCompletionSource<T>
, and you pass the state
parameter into the TaskCompletionSource<T>
constructor:
There really isn’t a need to read AsyncState
in modern code; it’s mainly important just because it implements IAsyncResult.AsyncState
.
CreationOptions
CreationOptions
merely allows you to read the task creation options that were used to create this task. You can specify these options when you create a task using the task constructor, Task.Factory.StartNew
, or TaskCompletionSource<T>
. I’ll cover the meanings of these options later, when we cover Task.Factory.StartNew
.
However, there’s almost no reason to read the task creation options once the task has been created. This would only be necessary if you were doing some really funky work with parent/child tasks or task scheduling - far beyond the normal scenarios for asynchronous or parallel tasks.
Conclusion
Once again none of these members are actually useful in real-world code.