C# 6.0 await in catch/finally

By | June 9, 2015

Advertisement from Google

C# 6.0 become more asynchronous-friendly than before. Finally, you can use await keyword in catch and finally blocks! Here is example:

class Program
{
    static void Main(string[] args)
    {
        do
        {
            Console.WriteLine("Before caller " + Thread.CurrentThread.ManagedThreadId);
            CallerMethod();
            Console.WriteLine("After caller " + Thread.CurrentThread.ManagedThreadId);
        } while (Console.ReadKey().Key != ConsoleKey.Q);
    }

    public static async void CallerMethod()
    {
        try
        {
            throw new Exception();
        }
        catch (Exception)
        {
            Console.WriteLine("Before catch await " + Thread.CurrentThread.ManagedThreadId);
            await TestAsync();
            Console.WriteLine("After catch await " + Thread.CurrentThread.ManagedThreadId);
        }
        finally
        {
            Console.WriteLine("Before finally await " + Thread.CurrentThread.ManagedThreadId);
            await TestAsync();
            Console.WriteLine("After finally await " + Thread.CurrentThread.ManagedThreadId);
        }
    }

    public static Task TestAsync()
    {
        return Task.Factory.StartNew(() =>
        {
            Console.WriteLine("Async method before sleep " + Thread.CurrentThread.ManagedThreadId);
            Thread.Sleep(1000);
            Console.WriteLine("Async method after sleep " + Thread.CurrentThread.ManagedThreadId);
        });
    }
}

Here is console output:

Before caller 1
Before catch await 1
Async method before sleep 3
After caller 1
Async method after sleep 3
After catch await 3
Before finally await 3
Async method before sleep 4
Async method after sleep 4
After finally await 4

Everything as we expected. Here is visualization of the threads:

C# 6.0 await catch finally thread

Internal Implementation

Generated IL code is pretty big for such small example, so I will not publish a whole code here. You can check it out on pastebin


Advertisement from Google

C# compiler will create two nested classes for this example. One will contain “awaiting” logic  and other just a wrapper for this anonymous method:

Console.WriteLine("Async method before sleep " + Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(1000);
Console.WriteLine("Async method after sleep " + Thread.CurrentThread.ManagedThreadId);

If you look in the IL code to the “awaiting” class you will find that it implements IAsyncStateMachine interface and all logic is in the MoveNext method.

This method uses System.Runtime.CompilerServices.TaskAwaiter class to wait for the threads to complete. It does this based on an internal state (integer variable).

Also, each await is “wrapped” with try\catch block. And all logic of waiting for a task to complete is there. Our original try\catch\finally block become more simple, almost empty try\catch block (without finally) which initialize internal state:

  .try
  {
	IL_0037:  nop
	IL_0038:  newobj     instance void [mscorlib]System.Exception::.ctor()
	IL_003d:  throw

  }  // end .try
  catch [mscorlib]System.Exception 
  {
	IL_003e:  stloc.1
	IL_003f:  ldarg.0
	IL_0040:  ldloc.1
	IL_0041:  stfld      object cs6await.Program/'<CallerMethod>d__1'::'<>s__3'
	IL_0046:  ldarg.0
	IL_0047:  ldc.i4.1
	IL_0048:  stfld      int32 cs6await.Program/'<CallerMethod>d__1'::'<>s__4'
	IL_004d:  leave.s    IL_004f

  }  // end handler

So, as you can see, await in catch\finally works in the same way as regular await construction. Nothing new where added to CIL to support this keyword in those blocks.

2 thoughts on “C# 6.0 await in catch/finally

  1. Pingback: The Morning Brew - Chris Alcock » The Morning Brew #1881

Leave a Reply

Your email address will not be published. Required fields are marked *