Click here to Skip to main content
15,886,786 members
Articles / Programming Languages / C#

Awaiting Expressions

Rate me:
Please Sign up or sign in to vote.
4.80/5 (19 votes)
28 Oct 2014CPOL5 min read 17.8K   1   33   2
Using the await keyword with Expression-Trees

The keywords await and async are probably the coolest new features in C# 5.0.
Generally, await is used when writing code that stretches across multiple points in time. From our perspective, the async method pauses execution once it hits await and will be resumed once the result of the await operation becomes available. This asynchronous behavior is closely associated with tasks and concurrent code.

What you might not know is that you can leverage await, even with no tasks or threads involved.
My goal today will be to enable awaiting on custom expressions like x == 5 * y.

Under the Hood

The first thing you need to know is that the await feature is just another case of pattern-based syntactic sugar. The C# compiler translates await into a set of predefined method calls and property look-ups. As long as the underlying methods are in place, the code will compile.
This is a common theme in C#; consider for example Foreach statements: as long as the object is able to provide the GetEnumerator, MoveNext, Current, and Dispose methods, you will be able to write a Foreach statement over the object. The same is true for LINQ query syntax.
So what is the underlying pattern that supports the await statements? Consider the following code:

C#
private async void Test()
{
    Part1();

    var x = await Something();

    Part2(x);
}

This will be translated into something similar to this:

C#
private async void Test()
{
    Part1(); // Do the first part

    var awaiter = Something().GetAwaiter(); 

    if (awaiter.IsCompleted) // If the result is ready
    {
        Part2(awaiter.GetResult()); // Just continue with the result.
    }
    else 
    {
        // Register a callback to get the result and continue the calculation upon completion:
        awaiter.OnCompleted(() => Part2(awaiter.GetResult())); 
        // At this point Test will return to it's caller.
        // Part2 will be continued somewhere in the future.
    }
}

This is (of course) an over-simplified example, as await can be used inside loops and branches, as a part of an expression evaluation, and in C# 6, even inside catch and finally blocks.
Nevertheless, as long as you provide GetAwaiter, IsCompleted, GetResult, and OnCompleted, the compiler will translate await statement into method calls to your implementation. Together, these four members constitute the Awaiter Pattern.

Battle-Plan

With this in mind, what would it take to use await on custom expressions like x == 5 * y?
First, we'd need to implement the Awaiter Pattern for custom expressions.
Next, we'd need some logic that would analyze the expression and let us know when the value of the expression had changed.
Finally, once the value of the expressions becomes true, we would trigger completion on our awaiter.

Implementing the Awaiter Pattern

Optimally, we'd like to use await on the expression tree data-structure.
Expression trees have a couple of useful properties:

  • They can be automatically generated from lambda expressions.
  • They can be analyzed and rewritten at run-time.
  • Any part of an expression tree can be compiled and converted into a delegate at run-time.

In general, the way you extend an existing type to support await is using an extension method:

C#
public static class ExpressionExtensions
{
    public static ExpressionAwaiter GetAwaiter(this Expression<Func<bool>> expression)
    {
        throw new NotImplementedException();
    }
}

In the case of an expression tree, this approach will not work. The code will compile, but you will not be able to write await x == 2.
The problem is that lambda expressions in C# don't have a type of their own (just like the null value). You may be aware of this problem if you've ever tried to compile something like var f = () => 5.
To my understanding, the compiler can actually infer the type of () => 5 to be Func<int>, but it cannot determine whether you intended f to reference a piece of executable code (anonymous function) or a piece of data (expression tree). That's why the final type of a lambda expression will always be inferred from its surroundings.

For instance, you could write:

C#
public Expression<Func<T>> Exp<T>(Expression<Func<T>> exp)
{
    return exp; // Do nothing.
}
public Func<T> Func<T>(Func<T> func)
{
    return func; // Do nothing.
}
//..
var a = Exp(() => 5); // Type of a is Expression<Func<int>>.
var b = Func(() => 5); // Type of a is Func<int>.

In this example, the type of each variable is decided at compile-time, but the methods themselves do nothing of value and could be optimized away. This means we would have to wrap our code in an explicit function:

C#
public static class Until
{
    public static ExpressionAwaitable BecomesTrue(Expression<Func<bool>> expression)
    {
        return new ExpressionAwaitable(expression);
    }
}

// Our awaitable wrapper to the original expression.
public class ExpressionAwaitable
{
    private readonly ExpressionAwaiter _awaiter = new ExpressionAwaiter();

    public ExpressionAwaitable(Expression<Func<bool>> expression)
    {
        // TODO: Put logic here.
    }

    public ExpressionAwaiter GetAwaiter()
    {
        return _awaiter;
    }
}

// Very simple awaiter that can be marked complete using the Complete method.
public class ExpressionAwaiter : INotifyCompletion
{
    private Action _continuation;

    public ExpressionAwaiter()
    {
        IsCompleted = false;
    }

    public bool IsCompleted { get; private set; }

    public void GetResult()
    {
        // Nothing to return.
    }

    public void Complete()
    {
        if (_continuation != null)
        {
            _continuation();
            IsCompleted = true;
        }
    }

    public void OnCompleted(Action continuation)
    {
        _continuation += continuation;
    }
}

// Usage:
await Until.BecomesTrue(() => txtBox.Text == Title);

Analyzing the Expression

Well, we can now compile await on an expression. It is still unclear how to translate this into useful run-time behavior. We need a way to notice when the value of the expression changes from false to true.

We could spin-up a thread and continuously check the value of the expression, but this approach has too many drawbacks. For one, the value could change to true and then back to false, and we could easily miss it.

Under reasonable assumptions, the value of an expression can change only when one of the objects involved in the expression changes. There are number of standard methods to know when an object has changed in the .NET Framework. One such standard is the INotifyPropertyChanged interface. As the name implies, it's designed to notify an external observer when an object’s properties are changed.

So this gives us the following algorithm:

  1. Scan the expression for objects implementing INotifyPropertyChanged.
  2. Subscribe to the PropertyChanged event on each of these objects.
  3. Each time an event is fired, evaluate the original expression.
  4. If the value is true, unsubscribe from all events and trigger completion on the awaiter.

The standard approach to analyzing expression trees is using the visitor pattern. To implement a new expression visitor, all you need to do is inherit from the ExpressionVisitor class in the System.Linq.Expressions namespace and override the methods visiting the types of expressions you wish to inspect.

We will implement a custom visitor that extracts all objects derived-from or implementing some generic type T:

C#
public class TypeExtractor<T> : ExpressionVisitor
{
    // Here's where the results will be stored:
    public IReadOnlyCollection<T> ExtractedItems { get { return _extractedItems; } }
    private readonly List<T> _extractedItems = new List<T>();

    private TypeExtractor() {}

    // Factory method.
    public static TypeExtractor<T> Extract<S>(Expression<Func<S>> expression)
    {
        var visitor = new TypeExtractor<T>();
        visitor.Visit(expression);
        return visitor;
    }

    private void ExtractFromNode(Type nodeReturnType, Expression node)
    {
        // Is the return type of the expression implements / derives from T?
        if (typeof(T).IsAssignableFrom(nodeReturnType))
        {
            // Cast node to an expression of form Func<T>
            var typedExpression = Expression.Lambda<Func<T>>(node);

            // Compile the expression (this will produce Func<T>)
            var compiledExpression = typedExpression.Compile();

            // Evaluate the expression (this will produce T)
            var expressionResult = compiledExpression();

            // Add the result to our collection of T's.
            _extractedItems.Add(expressionResult);
        }
    }

    // If the expression is a constant, then:
    protected override Expression VisitConstant(ConstantExpression node)
    {
        ExtractFromNode(node.Value.GetType(), node);
        return node;
    }
}

// Usage:
[TestMethod]
public void TypeExtractOnConst_ReturnsConst()
{ 
    var visitor = TypeExtractor<int>.Extract(() => 1);
    visitor.ExtractedItems.Should().Contain(1);
}

Of course, not all objects in our expression will be constants. Let's add a couple more cases:

C#
// Expression is of type x.Property or x._field
protected override Expression VisitMember(MemberExpression node)
{
    Visit(node.Expression); // For chained properties, like X.Y.Z

    node.Member.If()
               .Is<FieldInfo>(_ => ExtractFromNode(_.FieldType, node))
               .Is<PropertyInfo>(_ => ExtractFromNode(_.PropertyType, node));

    return node;
}

protected override Expression VisitParameter(ParameterExpression node)
{
    ExtractFromNode(node.Type, node);
    return node;
}

Putting Everything Together

Using TypeExtractor, we are able to identify all objects within an expression that implement INotifyPropertyChanged. Here's how to assemble it into an awaitable object:

C#
public class ExpressionAwaitable
{
    private readonly Func<bool> _predicate;
    private readonly List<INotifyPropertyChanged> _iNotifyPropChangedItems;
    private readonly ExpressionAwaiter _awaiter = new ExpressionAwaiter();

    public ExpressionAwaitable(Expression<Func<bool>> expression)
    {
        _predicate = expression.Compile(); // Generate a function that when invoked would evaluate our expression.

        if (_predicate()) // If the value is already true, complete the awaiter.
        {
            _awaiter.Complete();
        }
        else 
        {
            // Find all objects implementing INotifyPropertyChanged.
            _iNotifyPropChangedItems = TypeExtractor<INotifyPropertyChanged>
                    .Extract(expression).ExtractedItems.ToList();

            HookEvents(); // Register for notifications about changes.
        }
    }

    private void HookEvents()
    {
        foreach (var item in _iNotifyPropChangedItems)
        {
            item.PropertyChanged += NotifyPropChanged;
        }
    }

    private void UnhookEvents()
    {
        foreach (var item in _iNotifyPropChangedItems)
        {
            item.PropertyChanged -= NotifyPropChanged;
        }
    }

    private void NotifyPropChanged(object sender, PropertyChangedEventArgs agrs)
    {
        ExpressionChanged();
    }

    private void ExpressionChanged()
    {
        if (_predicate()) // Did the value became true?
        {
            UnhookEvents(); // Don't forget to unsubscribe.
            _awaiter.Complete(); // Signal completion.
        }
    }

    public ExpressionAwaiter GetAwaiter()
    {
        return _awaiter;
    }
}

In a similar fashion you can extend support to INotifyCollectionChanged in order to get notifications from observable collections.

Another type of observable object is the DependencyObject in WPF. Getting it right is a bit trickier, but it is important to our goal since many useful properties are, in fact, dependency properties. First, we need to extract all dependency properties from the expression. To do this, we will implement another expression visitor. Dependency properties are always properties so we can focus our efforts on the VisitMember function:

C#
protected override Expression VisitMember(MemberExpression node)
{
    Visit(node.Expression); // For chained properties.

    var member = node.Member;
    var declaringType = member.DeclaringType; 

    // Does the property live inside a DependencyObject?
    if (declaringType != null && typeof(DependencyObject).IsAssignableFrom(declaringType))
    {
        // Located the corresponding static field.
        var propField = declaringType.GetField(member.Name + "Property", BindingFlags.Public | BindingFlags.Static);

        if (propField != null)
        {
            // Extract the value like before.
            var typedExpression = Expression.Lambda<Func<DependencyObject>>(node.Expression);
            var compiledExpression = typedExpression.Compile();
            var expressionResult = compiledExpression();

            _extractedItems.Add(new DependencyPropertyInstance
            {
                Owner = expressionResult,
                // Get the corresponding dependency property:
                Property = propField.GetValue(expressionResult) as DependencyProperty
            });
        }
    }

    return node;
}

To get notifications from dependency properties, we will need to add code to HookEvents:

C#
private void HookEvents()
{
    ...
    foreach (var item in _iDPItems)
    {
        var descriptor = DependencyPropertyDescriptor.FromProperty(item.Property, item.Owner.GetType());
        descriptor.AddValueChanged(item.Owner, DependencyPropertyChanged);
    }
}

Usage:

C#
private async void Window_OnLoaded(object sender, RoutedEventArgs e)
{	 	
    // Wait until text box content is equal to forms title.
    // Note that the completion could be triggered both by changes
    // to the text box content and changes to the forms title. 
    await Until.BecomesTrue(() => txtBox.Text == Title);
    MessageBox.Show("Well done!");
}

You might ask, how is this better then a binding?
It is not, in WPF you can accomplish most of what we have discussed using MultiBinding and multi-value converters. However, in general, it would require much more code and effort. You can think of our approach as quick and dirty single-use binding.

In addition, I hope this post resolved some of the confusion surrounding the await keyword:
Here you have a completely single-threaded application using await to perform asynchronous operations.

You can download the source code here.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Team Leader Intel
Israel Israel
Currently member of Intel RealSense team, maintaining Intel RealSense Cross-platform SDK on GitHub (https://github.com/IntelRealSense/librealsense)

Comments and Discussions

 
QuestionThanks Pin
Nelek29-Oct-14 9:29
protectorNelek29-Oct-14 9:29 
GeneralMy Vote 5 Pin
Shemeemsha (ഷെമീംഷ)28-Oct-14 23:45
Shemeemsha (ഷെമീംഷ)28-Oct-14 23:45 
QuestionMy vote of 5! Pin
Volynsky Alex28-Oct-14 12:06
professionalVolynsky Alex28-Oct-14 12:06 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.