📜 ⬆️ ⬇️

They laugh at your callbacks or async / await "for the poor"

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(...) { // ... // get user id, if not specified if (string.IsNullOrEmpty(uid)) { var getUserIdTask = lient.GetUserId(...); yield return getUserIdTask; // await uid= getUserIdTask.Result.uid; } // login var loginTask = lient.Login(...); yield return loginTask; // await var sessionId = loginTask.Result.SessionId; // getting user's profile var getUserInfoTask = lient.GetUserInfo(...); yield return getUserInfoTask; // await var userInfo = getUserInfoTask.Result; // ... yield return userInfo; // return } 

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:
  1. Create a root task and return to the caller.
  2. Rotate the iterator
  3. If the Task is returned, then we are waiting for its completion through ContinueWith with the transition to Step # 2.
  4. If the error returned, we set Exception for the horse Task
  5. If the value is returned, we end the horse Task with this result.
  6. 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(...)); //     Task<UserInfo> loginTask = TaskUtils.FromIterator<UserInfo>(this.Login(...)); 

Optionally, you can specify:


Conclusion

Pros:



Minuses:


Most of the cons can be overcome in one way or another.

Errors in the text can be sent to the LAN.
Source code

Source: https://habr.com/ru/post/174799/


All Articles