Understanding C# async / await (2) Awaitable / Awaiter Pattern

What is awaitable

Part 1 shows that any Task is awaitable. Actually there are other awaitable types. Here is an example:

Task<int> task = new Task<int>(() => 0);
int result = await task.ConfigureAwait(false); // Returns a ConfiguredTaskAwaitable<TResult>.

The returned ConfiguredTaskAwaitable<TResult> struct is awaitable. And it is not Task at all:

public struct ConfiguredTaskAwaitable<TResult>
{
    private readonly ConfiguredTaskAwaiter m_configuredTaskAwaiter;

    internal ConfiguredTaskAwaitable(Task<TResult> task, bool continueOnCapturedContext)
    {
        this.m_configuredTaskAwaiter = new ConfiguredTaskAwaiter(task, continueOnCapturedContext);
    }

    public ConfiguredTaskAwaiter GetAwaiter()
    {
        return this.m_configuredTaskAwaiter;
    }
}

It has one GetAwaiter() method. Actually in part 1 we have seen that Task has GetAwaiter() method too:

public class Task
{
    public TaskAwaiter GetAwaiter()
    {
        return new TaskAwaiter(this);
    }
}

public class Task<TResult> : Task
{
    public new TaskAwaiter<TResult> GetAwaiter()
    {
        return new TaskAwaiter<TResult>(this);
    }
}

Task.Yield() is a another example:

await Task.Yield(); // Returns a YieldAwaitable.

The returned YieldAwaitable is not Task either:

public struct YieldAwaitable
{
    public YieldAwaiter GetAwaiter()
    {
        return default(YieldAwaiter);
    }
}

Again, it just has one GetAwaiter() method. In this article, we will look at what is awaitable.

The awaitable / awaiter pattern

By observing different awaitable / awaiter types, we can tell that an object is awaitable if

  • It has a GetAwaiter() method (instance method or extension method);
  • Its GetAwaiter() method returns an awaiter. An object is an awaiter if:
    • It implements INotifyCompletion or ICriticalNotifyCompletion interface;
    • It has an IsCompleted, which has a getter and returns a Boolean;
    • it has a GetResult() method, which returns void, or a result.

This awaitable / awaiter pattern is very similar to the iteratable / iterator pattern. Here is the interface definitions of iteratable / iterator:

public interface IEnumerable
{
    IEnumerator GetEnumerator();
}

public interface IEnumerator
{
    object Current { get; }

    bool MoveNext();

    void Reset();
}

public interface IEnumerable<out T> : IEnumerable
{
    IEnumerator<T> GetEnumerator();
}

public interface IEnumerator<out T> : IDisposable, IEnumerator
{
    T Current { get; }
}

In case you are not familiar with the out keyword, please find out the explanation in Understanding C# Covariance And Contravariance (2) Interfaces.

The “missing” IAwaitable / IAwaiter interfaces

Similar to IEnumerable and IEnumerator interfaces, awaitable / awaiter can be visualized by IAwaitable / IAwaiter interfaces too. This is the non-generic version:

public interface IAwaitable
{
    IAwaiter GetAwaiter();
}

public interface IAwaiter : INotifyCompletion // or ICriticalNotifyCompletion
{
    // INotifyCompletion has one method: void OnCompleted(Action continuation);

    // ICriticalNotifyCompletion implements INotifyCompletion,
    // also has this method: void UnsafeOnCompleted(Action continuation);

    bool IsCompleted { get; }

    void GetResult();
}

Please notice GetResult() returns void here. Task.GetAwaiter() / TaskAwaiter.GetResult() is of such case.

And this is the generic version:

public interface IAwaitable<out TResult>
{
    IAwaiter<TResult> GetAwaiter();
}

public interface IAwaiter<out TResult> : INotifyCompletion // or ICriticalNotifyCompletion
{
    bool IsCompleted { get; }

    TResult GetResult();
}

Here the only difference is, GetResult() return a result. Task<TResult>.GetAwaiter() / TaskAwaiter<TResult>.GetResult() is of this case.

Please notice .NET does not define these IAwaitable / IAwaiter interfaces at all. As an UI designer, I guess the reason is, IAwaitable interface will constraint GetAwaiter() to be instance method. Actually C# supports both GetAwaiter() instance method and GetAwaiter() extension method.

Here I use these interfaces only for better visualizing what is awaitable / awaiter. Now, if looking at above ConfiguredTaskAwaitable / ConfiguredTaskAwaiter, YieldAwaitable / YieldAwaiter, Task / TaskAwaiter pairs again, they all “implicitly” implement these “missing” IAwaitable / IAwaiter interfaces. In the next part, we will see how to implement awaitable / awaiter.

Await any function / action

In C# await cannot be used with lambda. This code:

int result = await (() => 0);

will cause a compiler error:

Cannot await 'lambda expression'

This is easy to understand because this lambda expression (() => 0) may be a function or a expression tree. Obviously we mean function here, and we can tell compiler in this way:

int result = await new Func<int>(() => 0);

It causes an different error:

Cannot await 'System.Func<int>'

OK, now the compiler is complaining the type instead of syntax. With the understanding of the awaitable / awaiter pattern, Func<TResult> type can be easily made into awaitable.

GetAwaiter() instance method, using IAwaitable / IAwaiter interfaces

First, similar to above ConfiguredTaskAwaitable<TResult>, a FuncAwaitable<TResult> can be implemented to wrap Func<TResult>:

internal struct FuncAwaitable<TResult> : IAwaitable<TResult>
{
    private readonly Func<TResult> function;

    public FuncAwaitable(Func<TResult> function)
    {
        this.function = function;
    }

    public IAwaiter<TResult> GetAwaiter()
    {
        return new FuncAwaiter<TResult>(this.function);
    }
}

FuncAwaitable<TResult> wrapper is used to implement IAwaitable<TResult>, so it has one instance method, GetAwaiter(), which returns a IAwaiter<TResult>, which wraps that Func<TResult> too. FuncAwaiter<TResult> is used to implement IAwaiter<TResult>:

public struct FuncAwaiter<TResult> : IAwaiter<TResult>
{
    private readonly Task<TResult> task;

    public FuncAwaiter(Func<TResult> function)
    {
        this.task = new Task<TResult>(function);
        this.task.Start();
    }

    bool IAwaiter<TResult>.IsCompleted
    {
        get
        {
            return this.task.IsCompleted;
        }
    }

    TResult IAwaiter<TResult>.GetResult()
    {
        return this.task.Result;
    }

    void INotifyCompletion.OnCompleted(Action continuation)
    {
        new Task(continuation).Start();
    }
}

Now a function can be awaited in this way:

int result = await new FuncAwaitable<int>(() => 0);

GetAwaiter() extension method

As IAwaitable shows, all that an awaitable needs is just a GetAwaiter() method. In above code, FuncAwaitable<TResult> is created as a wrapper of Func<TResult> and implements IAwaitable<TResult>, so that there is a  GetAwaiter() instance method. If a GetAwaiter() extension method  can be defined for Func<TResult>, then FuncAwaitable<TResult> is no longer needed:

public static class FuncExtensions
{
    public static IAwaiter<TResult> GetAwaiter<TResult>(this Func<TResult> function)
    {
        return new FuncAwaiter<TResult>(function);
    }
}

So a Func<TResult> function can be directly awaited:

int result = await new Func<int>(() => 0);

Using the existing awaitable / awaiter - Task / TaskAwaiter

Remember the most frequently used awaitable / awaiter - Task / TaskAwaiter. With Task / TaskAwaiter, FuncAwaitable / FuncAwaiter are no longer needed:

public static class FuncExtensions
{
    public static TaskAwaiter<TResult> GetAwaiter<TResult>(this Func<TResult> function)
    {
        Task<TResult> task = new Task<TResult>(function);
        task.Start();
        return task.GetAwaiter(); // Returns a TaskAwaiter<TResult>.
    }
}

Similarly, with this extension method:

public static class ActionExtensions
{
    public static TaskAwaiter GetAwaiter(this Action action)
    {
        Task task = new Task(action);
        task.Start();
        return task.GetAwaiter(); // Returns a TaskAwaiter.
    }
}

an action can be awaited as well:

await new Action(() => { });

Now any function / action can be awaited:

await new Action(() => HelperMethods.IO()); // or: await new Action(HelperMethods.IO);

If function / action has parameter(s), closure can be used:

int arg0 = 0;
int arg1 = 1;
int result = await new Action(() => HelperMethods.IO(arg0, arg1));

Using Task.Run()

The above code is used to demonstrate how awaitable / awaiter can be implemented. Because it is a common scenario to await a function / action, so .NET provides a built-in API: Task.Run():

public class Task2
{
    public static Task Run(Action action)
    {
        // The implementation is similar to:
        Task task = new Task(action);
        task.Start();
        return task;
    }

    public static Task<TResult> Run<TResult>(Func<TResult> function)
    {
        // The implementation is similar to:
        Task<TResult> task = new Task<TResult>(function);
        task.Start();
        return task;
    }
}

In reality, this is how we await a function:

int result = await Task.Run(() => HelperMethods.IO(arg0, arg1));

and await a action:

await Task.Run(() => HelperMethods.IO());
Published Thursday, November 8, 2012 12:10 AM by Dixin
Filed under: , , ,

Comments

# re: Understanding C# async / await (2) Awaitable / Awaiter Pattern

Friday, November 9, 2012 11:16 PM by SGWellens

FYI:  Those weird comments you are getting are mostly spammers trying to get links to their sites embedded in your blog so they get higher SEO scores.

# re: Understanding C# async / await (2) Awaitable / Awaiter Pattern

Sunday, April 7, 2013 10:56 PM by Whitlock

whoah this blog is fantastic i love reading your articles.

Keep up the

good work! You know, lots of people are looking around for this

information, you could help them greatly.

# re: Understanding C# async / await (2) Awaitable / Awaiter Pattern

Monday, April 8, 2013 2:43 AM by Haight

I am continuously searching online for posts that can assist me.

Thx!

# re: Understanding C# async / await (2) Awaitable / Awaiter Pattern

Wednesday, April 10, 2013 7:30 AM by Gomes

I’d have to test with you here. Which is not something I usually do!

I get pleasure from reading a put up that can make

people think. Also, thanks for

allowing me to remark!

# re: Understanding C# async / await (2) Awaitable / Awaiter Pattern

Wednesday, April 10, 2013 12:52 PM by Webster

certainly like your web site but you have to check the

spelling on quite a few of your posts. Several of them are rife with

spelling issues

and I find it very bothersome to tell the truth nevertheless I’ll certainly come

back again.

# re: Understanding C# async / await (2) Awaitable / Awaiter Pattern

Thursday, April 11, 2013 12:01 AM by Workman

When I initially commented I clicked the -Notify me

when new comments are added-

checkbox and now every time a remark is added I get 4 emails with the identical comment.

Is there any method you may take away me

from that service? Thanks!

# re: Understanding C# async / await (2) Awaitable / Awaiter Pattern

Thursday, April 11, 2013 4:18 AM by Guthrie

You must participate in a contest for

probably the greatest blogs on the web. I will

recommend this web site!

# re: Understanding C# async / await (2) Awaitable / Awaiter Pattern

Thursday, April 11, 2013 3:18 PM by Call

Hi there, i read your blog occasionally and i own a similar one and i was just

curious if you get a lot of spam responses?

If so how do you prevent it, any plugin or anything you

can recommend? I get so much lately it's driving me crazy so any assistance is very much appreciated.

# re: Understanding C# async / await (2) Awaitable / Awaiter Pattern

Friday, April 12, 2013 12:37 AM by Rushing

Somebody essentially assist to make

significantly posts I'd state. That is the first time I

frequented your web page and thus far? I amazed with the

research you made to create this actual submit

amazing. Wonderful task!

# re: Understanding C# async / await (2) Awaitable / Awaiter Pattern

Friday, April 12, 2013 6:12 AM by Reeves

Would you be involved in exchanging

hyperlinks?

# re: Understanding C# async / await (2) Awaitable / Awaiter Pattern

Friday, April 12, 2013 10:43 AM by Frasier

Hi there, just became aware of your blog through Google, and found that it is truly

informative. I’m gonna watch out for brussels.

I’ll be grateful if you continue

this in future. Numerous people will be benefited from your writing.

Cheers!

# re: Understanding C# async / await (2) Awaitable / Awaiter Pattern

Friday, April 12, 2013 11:10 AM by Piper

Hi there, simply turned into alert to your blog

through Google, and located that it's truly informative. I am going to

watch out for brussels. I’ll appreciate in the event you proceed this in future. Many other people shall be benefited from your writing. Cheers!

# re: Understanding C# async / await (2) Awaitable / Awaiter Pattern

Friday, April 12, 2013 6:07 PM by Gould

Hmm is anyone else experiencing problems with the pictures on this blog loading?

I'm trying

to determine if its a problem on my end or if it's the blog.

Any feed-back would be greatly appreciated.

# re: Understanding C# async / await (2) Awaitable / Awaiter Pattern

Saturday, April 13, 2013 8:49 AM by Mccallum

I am extremely impressed with your writing talents as smartly as with the format in your

blog. Is this a paid subject matter or did you modify it

your self? Either way stay up the excellent high quality writing, it’s

rare to peer a great blog like this one these days..

# re: Understanding C# async / await (2) Awaitable / Awaiter Pattern

Saturday, April 13, 2013 9:10 AM by Card

A person necessarily assist to make severely articles I might state.

That is the very first time I

frequented your website page and up to now?

I amazed with the

research you made to create this actual publish extraordinary.

Great task!

# re: Understanding C# async / await (2) Awaitable / Awaiter Pattern

Monday, April 15, 2013 11:07 AM by Sommer

What’s Taking place i'm new to this, I stumbled upon this I have found It

absolutely helpful and it has aided me out loads. I'm hoping to contribute & aid

different users like its helped me. Great

job.

# re: Understanding C# async / await (2) Awaitable / Awaiter Pattern

Monday, April 15, 2013 5:57 PM by Arteaga

I comment whenever I especially enjoy a article on a site or

I have something to contribute to the conversation. Usually it's caused by the passion communicated in the article I looked at. And after this article Understanding C# async / await (2) Awaitable / Awaiter Pattern - Dixin's

Blog. I was actually moved enough to drop a thought :-P I actually do

have some questions for you if you usually do not mind.

Could it be just me or does it give the impression like some of these remarks appear like they

are left by brain dead visitors? :-P And, if you are writing at additional places,

I'd like to keep up with anything new you have to post. Could you make a list every one of your shared pages like your linkedin profile, Facebook page or twitter feed?

# re: Understanding C# async / await (2) Awaitable / Awaiter Pattern

Monday, April 15, 2013 7:47 PM by Mead

I’ll immediately take hold of your rss feed as I

can't to find your e-mail subscription hyperlink or e-newsletter service. Do

you've any? Kindly permit me recognize in

order that I may subscribe. Thanks.

# re: Understanding C# async / await (2) Awaitable / Awaiter Pattern

Tuesday, April 16, 2013 12:48 AM by Carranza

Do you have a spam issue on this site; I also am a blogger,

and I was curious about your situation; we have created some nice procedures and we

are looking to exchange solutions with other folks, please shoot me an email if

interested.

# re: Understanding C# async / await (2) Awaitable / Awaiter Pattern

Thursday, April 18, 2013 2:52 AM by Herzog

It's really a great and helpful piece of information. I'm happy that you

simply shared this helpful info with us. Please keep us informed like this.

Thanks for sharing.

# re: Understanding C# async / await (2) Awaitable / Awaiter Pattern

Thursday, April 18, 2013 9:12 AM by Francis

Its such as you learn my mind! You seem to understand a lot about

this, such as you wrote the ebook in it or something.

I feel that you simply could do with a few p.c.

to force the message house a bit, however instead of that,

this is excellent blog. A great read. I will

definitely be back.

# re: Understanding C# async / await (2) Awaitable / Awaiter Pattern

Friday, April 19, 2013 5:16 AM by Florez

This is my first time pay a visit at here and i am really impressed to

read everthing at alone place.

# re: Understanding C# async / await (2) Awaitable / Awaiter Pattern

Friday, April 19, 2013 5:25 AM by Gallo

This is really interesting, You're a very skilled blogger. I've joined your rss feed and look forward to seeking more of your excellent post.

Also, I've shared your site in my social networks!

# re: Understanding C# async / await (2) Awaitable / Awaiter Pattern

Sunday, April 21, 2013 9:27 AM by Rhoden

Magnificent goods from you, man. I have understand

your stuff previous to and

you are just extremely excellent. I really like what

you've acquired here, certainly like what you're

saying and the way in which you

say it. You make it entertaining and you still care

for to keep it smart. I

can not wait to read far more from you. This is really a

tremendous website.

# re: Understanding C# async / await (2) Awaitable / Awaiter Pattern

Tuesday, May 7, 2013 5:40 AM by Vest

Magnificent beat ! I would like to apprentice while you amend your site, how could i subscribe for

a weblog website? The account helped me a appropriate deal.

I had been tiny bit acquainted of this your broadcast offered vibrant clear concept

# re: Understanding C# async / await (2) Awaitable / Awaiter Pattern

Wednesday, May 8, 2013 6:49 AM by Kendrick

I've been surfing on-line more than 3 hours nowadays, yet I never discovered any attention-grabbing article like yours. It is lovely worth sufficient for me. In my opinion, if all site owners and bloggers made just right content as you probably did, the internet shall be much more helpful than ever before.

# re: Understanding C# async / await (2) Awaitable / Awaiter Pattern

Friday, May 17, 2013 6:51 AM by Carvalho

Hi to every one, it's really a pleasant for me to visit this website, it includes precious Information.

# re: Understanding C# async / await (2) Awaitable / Awaiter Pattern

Wednesday, July 10, 2013 11:57 PM by Daughtry

Great write-up, I’m regular visitor of one’s blog, maintain up the

excellent operate, and It is going to be a regular visitor for a lengthy time.

# re: Understanding C# async / await (2) Awaitable / Awaiter Pattern

Saturday, December 14, 2013 4:50 PM by dvdLOCFbFzNVoV

L5UKAC Great blog article.Much thanks again. Awesome.

# re: Understanding C# async / await (2) Awaitable / Awaiter Pattern

Tuesday, December 24, 2013 7:31 AM by Kruse

I'm not sure why but this website is loading extremely slow for me.

Is anyone else having this issue or is it a problem on

my end? I'll check back later on and see if the problem still exists.

# re: Understanding C# async / await (2) Awaitable / Awaiter Pattern

Wednesday, January 8, 2014 3:15 AM by OKICWmUfHwn

AKOPLg Major thanks for the blog article.Really looking forward to read more. Cool.

# re: Understanding C# async / await (2) Awaitable / Awaiter Pattern

Saturday, January 18, 2014 1:32 PM by oMJqUoeLYYYOs

utufqh Say, you got a nice blog. Keep writing.

Leave a Comment

(required) 
(required) 
(optional)
(required)