AsyncRewriter

Thong Nguyen edited this page Jul 26, 2018 · 9 revisions

Introduction

Shaolinq.AsynRewriter automatically converts your sync methods into async methods using the Roslyn compiler to parse and generate equivalent async code. Library developers quickly realise that the code for async is pretty much the same as their sync code except that calls to Method1() are replaced with await Method1Async() calls which results in a lot of copy & paste code. Shaolinq.AsyncRewriter solves this issue by generating the code for you.

Features

  • Source based so does not require shipping dependent assemblies
  • Supports rewriting interface and abstract methods
  • Supports matching asynchronous methods from extension methods
  • Supports methods with params
  • Supports methods with expression bodies
  • Supports generating async methods with different method visibility from the source method

Installation

Shaolinq.AsyncRewriter is available as a NuGet package (Shaolinq.AsyncRewriter). Create a new class library project and then add the Shaolinq.AsyncRewriter NuGet Package. The package will automatically add some pre-build steps to your csproj to generate the async code before the full compile. Additionally the package will add a class named RewriteAsyncAttribute to your project. Simply decorate any method in your project with the [RewriteAsync] attribute to have an equivalent async method generated. You will need to make sure any types containing [RewriteAsync] are declared as partial because AsyncRewriter will add async methods to the type by outputting a matching partial classes.

How it works

AsyncRewriter will generate a source file named GeneratedAsync.cs. All types with methods attributed with [RewriteAsync] will get equivalent async methods (two async methods for each sync method) outputted into GeneratedAsync.cs.

All methods are translated as follows:

  • For each attributed sync method two methods are generated with the name and "Async" appended. One is a method that takes a CancellationToken and one that does not. The CancellationToken parameter is inserted after the last non-default and non-params parameter
  • For all method bodies of generated async methods, method calls are replaced with await asynchronous calls if one is available.
  • Both static and instance methods are replaced with asynchronous versions where possible.

Candidate async method selection

Candidate async methods for synchronous method calls are chosen from the following set:

  • An async version of the method automatically generated by AsyncRewriter because the method was attributed with [RewriteAsync]
  • An manually written async version of the method - defined by a method with the same name and Async suffix. If a CancellationToken version of the method is defined then it is preferred.
  • An extension method is available that matches the name and signature of the instance method being called.

Examples

Source:

[RewriteAsync]
public virtual IDbConnection OpenServerConnection()
{
    if (this.dbProviderFactory == null)
    {
        this.dbProviderFactory = this.CreateDbProviderFactory();
    }

    var retval = this.dbProviderFactory.CreateConnection();

    retval.ConnectionString = this.ServerConnectionString;
    retval.Open();

    return retval;
}

Generated code:

public virtual Task<IDbConnection> OpenServerConnectionAsync()
{
    return this.OpenServerConnectionAsync(CancellationToken.None);
}

public virtual async Task<IDbConnection> OpenServerConnectionAsync(CancellationToken cancellationToken)
{
    if (this.dbProviderFactory == null)
    {
        this.dbProviderFactory = this.CreateDbProviderFactory();
    }

    var retval = this.dbProviderFactory.CreateConnection();
    retval.ConnectionString = this.ServerConnectionString;
    await retval.OpenAsync(cancellationToken).ConfigureAwait(false);
    return retval;
}

Source:

public partial interface Foo
{
    [RewriteAsync]
    string Bar(int param, params string[] args);
}

Generated code:

public partial interface Foo
{
    Task<string> BarAsync(int arg1, params string[] args);
    Task<string> BarAsync(int arg1, CancellationToken cancellationToken, params string[] args);
}
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.