Using C # 5 Features (async and await) in .NET 2.0

    Dedicated to those 45% of .NET developers who are still sitting on 2.0-3.5 frameworks.

    Yes, you heard right. async and await in the second subnet. But first things first.

    What for?

    At some point, I was tired of manually tinkering with writing asynchronous code. Async / awat looked too tasty not to try. Knowing that when adding new features to the language and the compiler, Microsoft does not bind them tightly to the framework (for example, extension methods and LINQ can be used perfectly in the second .NET if you declare System.Runtime.CompilerServices.ExtensionAttribute somewhere), and seeing Async CTP, adding the ability to use async / await in the 2010th studio when using .NET 4.0 as the target framework, I thought, why not?


    Studying the results of the compiler’s activity and the dependencies of the framework classes, I realized that adding one attribute without the code is not enough. We need a full implementation, but where can I get it? And here Mono comes to the rescue with its implementation of BCL under the MIT license. Well, brazenly download Mono 3.10.1 and pull out System.Threading.Tasks and the necessary classes from System.Runtime.CompilerServices cleanly. Depending on their dependencies, they pull a lot of things, but for the most part everything is decided by simple copying. Two problems arise:

    1) OperationCanceledException does not know anything about CancellationToken. Create the class OperationCancelledExceptionExt that knows. Throws it CancellationToken.ThrowIfCancelled, so our code does not need to know about it.

    2) ExceptionDispatchInfo. This is where the real problems begin. The class allows you not to lose stack trace when throwing an exception again, which is very useful for async / await, for which everything was started. Mono implements it through the internal method of its implementation of the Exception class, so these sources will not really help us. Well, we climb into the source code of the framework. After a quick analysis, we understand that there is a certain mechanism used by runtime to support stackraces when using Remoting.
    We analyze, issue this code (extracting the required Field / MethodInfo and saving the state in another place):

    		public void Throw ()
    				throw _exception;
    				InternalPreserveStackTrace.Invoke (_exception, new object[0]);
    				RemoteStackTrace.SetValue (_exception, _stackTrace);
    				Source.SetValue (_exception, _source);

    We get the behavior close to the necessary:
    The exception is thrown as if it had flowed from the point where it was captured to the point where the Throw method is called.

    For lack of better solutions, we leave it this way.

    We compile, connect to the project ... We observe the picture: async / await work, but for some reason are marked in red. It is treated by setting the correct version of the language in the project properties.

    How to use

    Visual Studio 2010 requires the installation of Async CTP to build . To install, you need to perform a number of non-obvious actions, such as preliminary removal of MVC3 and all updates to the studio, released after SP1.
    In Visual Studio 2012, I did not check, but it should start.

    Next, we connect MonoLib.dll to the project and use it, not forgetting to set in the project properties that we have C # 5. A small demo is in the same place.

    Additions and improvements

    Since Tuple and Action / Func overloads were needed to build the tasks, it was decided not to get too small and put LINQ2Objects into the library. If desired, you can delete.

    The MonoLib.Async.Extensions class was created, where several useful extension methods were added, half of which are copied with minor changes from this document . By the way, I highly recommend reading the document, it sets out in detail how to use tasks and async / await correctly, as well as how to correctly wrap code in them using other models of asynchronous calls.

    MonoLib.dll sources (borrowings from Mono + edits + ExceptionDispatchInfo) are available on GitHub , you can improve the solution.

    Also popular now: