Do you have a project on .NET 4.0 and you are tired of the “noodles” of callbacks? Would you like to use async / await in your project, but the team leader faces a sky penalty for changing platforms? If installing the patch on the framework and the studio for you is a valid solution, then you are
here . If not, there is another solution.

(
for guru: inside cortina on yield )
Some theory
The async method is a
coroutine that goes to each await and is restored from this point to complete the wait (the author
knows that execution is not always interrupted by await and that not only Task instances can be “expected”). So, starting with the second version of dotnet, you can easily create coroutines using the yield keyword. We will use this tool.
Concept
I would like to write as in C # 5.0, and at the same time do not put any language extensions. Unfortunately this will not work. But there is such an option:
private IEnumerable Login(...) {
All that is returned through a yield return and is not a successor of Task is considered the result of the async method execution.
')
Implementation
The code is
here .
The mechanism of operation is simple:
- Create a root task and return to the caller.
- Rotate the iterator
- If the Task is returned, then we are waiting for its completion through ContinueWith with the transition to Step # 2.
- If the error returned, we set Exception for the horse Task
- If the value is returned, we end the horse Task with this result.
- If the iterator is over, then end the task Task with the standard result.
In all options, completion on the iterator will be called Dispose, which will lead to the release of resources in using and try / finally blocks.
You can start a new asynchronous task by calling the
FromIterator method:
private IEnumerable Login(...) { ... } Task loginTask = TaskUtils.FromIterator(this.Login(...));
Optionally, you can specify:
- state - the state that will go to Task.AsyncState
- creationFlags - TaskCreationOptions for the root task. Setting TaskCreationOptions.LongRunning says that you really do not want to block the current thread and all work must be done in another thread
- cancellationToken - the token of the interruption of the async-method execution process, transmitted inwards wherever possible
Conclusion
Pros:
- Compact and clean
- You can not be afraid for unmanaged resources, using, try / catch work
- Does not require patches and add. libraries
- Will work in Mono
Minuses:
- The async method returns an IEnumerable, not a Task. Sometimes you have to create an additional method that returns Task.
- "Expect" can only Task instances
- Errors of "expected" tasks cannot be processed through try / catch (it is possible through ContinueWith). If an error occurs in the expected task, the root task is set to Exception and the execution thread no longer visits the async method.
- The internal implementation class (TaskBuilder) does not generate references to itself, except when subscribing to ContinueWith in the expected tasks, and there is a possibility of assembling it with GC
Most of the cons can be overcome in one way or another.
Errors in the text can be sent to the LAN.
Source code