Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 4537990
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 21, 20262026-05-21T14:45:00+00:00 2026-05-21T14:45:00+00:00

Yesterday I was giving a talk about the new C# async feature, in particular

  • 0

Yesterday I was giving a talk about the new C# “async” feature, in particular delving into what the generated code looked like, and the GetAwaiter() / BeginAwait() / EndAwait() calls.

We looked in some detail at the state machine generated by the C# compiler, and there were two aspects we couldn’t understand:

  • Why the generated class contains a Dispose() method and a $__disposing variable, which never appear to be used (and the class doesn’t implement IDisposable).
  • Why the internal state variable is set to 0 before any call to EndAwait(), when 0 normally appears to mean “this is the initial entry point”.

I suspect the first point could be answered by doing something more interesting within the async method, although if anyone has any further information I’d be glad to hear it. This question is more about the second point, however.

Here’s a very simple piece of sample code:

using System.Threading.Tasks;

class Test
{
    static async Task<int> Sum(Task<int> t1, Task<int> t2)
    {
        return await t1 + await t2;
    }
}

… and here’s the code which gets generated for the MoveNext() method which implements the state machine. This is copied directly from Reflector – I haven’t fixed up the unspeakable variable names:

public void MoveNext()
{
    try
    {
        this.$__doFinallyBodies = true;
        switch (this.<>1__state)
        {
            case 1:
                break;

            case 2:
                goto Label_00DA;

            case -1:
                return;

            default:
                this.<a1>t__$await2 = this.t1.GetAwaiter<int>();
                this.<>1__state = 1;
                this.$__doFinallyBodies = false;
                if (this.<a1>t__$await2.BeginAwait(this.MoveNextDelegate))
                {
                    return;
                }
                this.$__doFinallyBodies = true;
                break;
        }
        this.<>1__state = 0;
        this.<1>t__$await1 = this.<a1>t__$await2.EndAwait();
        this.<a2>t__$await4 = this.t2.GetAwaiter<int>();
        this.<>1__state = 2;
        this.$__doFinallyBodies = false;
        if (this.<a2>t__$await4.BeginAwait(this.MoveNextDelegate))
        {
            return;
        }
        this.$__doFinallyBodies = true;
    Label_00DA:
        this.<>1__state = 0;
        this.<2>t__$await3 = this.<a2>t__$await4.EndAwait();
        this.<>1__state = -1;
        this.$builder.SetResult(this.<1>t__$await1 + this.<2>t__$await3);
    }
    catch (Exception exception)
    {
        this.<>1__state = -1;
        this.$builder.SetException(exception);
    }
}

It’s long, but the important lines for this question are these:

// End of awaiting t1
this.<>1__state = 0;
this.<1>t__$await1 = this.<a1>t__$await2.EndAwait();

// End of awaiting t2
this.<>1__state = 0;
this.<2>t__$await3 = this.<a2>t__$await4.EndAwait();

In both cases the state is changed again afterwards before it’s next obviously observed… so why set it to 0 at all? If MoveNext() were called again at this point (either directly or via Dispose) it would effectively start the async method again, which would be wholly inappropriate as far as I can tell… if and MoveNext() isn’t called, the change in state is irrelevant.

Is this simply a side-effect of the compiler reusing iterator block generation code for async, where it may have a more obvious explanation?

Important disclaimer

Obviously this is just a CTP compiler. I fully expect things to change before the final release – and possibly even before the next CTP release. This question is in no way trying to claim this is a flaw in the C# compiler or anything like that. I’m just trying to work out whether there’s a subtle reason for this that I’ve missed 🙂

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-21T14:45:02+00:00Added an answer on May 21, 2026 at 2:45 pm

    Okay, I finally have a real answer. I sort of worked it out on my own, but only after Lucian Wischik from the VB part of the team confirmed that there really is a good reason for it. Many thanks to him – and please visit his blog (on archive.org), which rocks.

    The value 0 here is only special because it’s not a valid state which you might be in just before the await in a normal case. In particular, it’s not a state which the state machine may end up testing for elsewhere. I believe that using any non-positive value would work just as well: -1 isn’t used for this as it’s logically incorrect, as -1 normally means "finished". I could argue that we’re giving an extra meaning to state 0 at the moment, but ultimately it doesn’t really matter. The point of this question was finding out why the state is being set at all.

    The value is relevant if the await ends in an exception which is caught. We can end up coming back to the same await statement again, but we mustn’t be in the state meaning "I’m just about to come back from that await" as otherwise all kinds of code would be skipped. It’s simplest to show this with an example. Note that I’m now using the second CTP, so the generated code is slightly different to that in the question.

    Here’s the async method:

    static async Task<int> FooAsync()
    {
        var t = new SimpleAwaitable();
        
        for (int i = 0; i < 3; i++)
        {
            try
            {
                Console.WriteLine("In Try");
                return await t;
            }                
            catch (Exception)
            {
                Console.WriteLine("Trying again...");
            }
        }
        return 0;
    }
    

    Conceptually, the SimpleAwaitable can be any awaitable – maybe a task, maybe something else. For the purposes of my tests, it always returns false for IsCompleted, and throws an exception in GetResult.

    Here’s the generated code for MoveNext:

    public void MoveNext()
    {
        int returnValue;
        try
        {
            int num3 = state;
            if (num3 == 1)
            {
                goto Label_ContinuationPoint;
            }
            if (state == -1)
            {
                return;
            }
            t = new SimpleAwaitable();
            i = 0;
          Label_ContinuationPoint:
            while (i < 3)
            {
                // Label_ContinuationPoint: should be here
                try
                {
                    num3 = state;
                    if (num3 != 1)
                    {
                        Console.WriteLine("In Try");
                        awaiter = t.GetAwaiter();
                        if (!awaiter.IsCompleted)
                        {
                            state = 1;
                            awaiter.OnCompleted(MoveNextDelegate);
                            return;
                        }
                    }
                    else
                    {
                        state = 0;
                    }
                    int result = awaiter.GetResult();
                    awaiter = null;
                    returnValue = result;
                    goto Label_ReturnStatement;
                }
                catch (Exception)
                {
                    Console.WriteLine("Trying again...");
                }
                i++;
            }
            returnValue = 0;
        }
        catch (Exception exception)
        {
            state = -1;
            Builder.SetException(exception);
            return;
        }
      Label_ReturnStatement:
        state = -1;
        Builder.SetResult(returnValue);
    }
    

    I had to move Label_ContinuationPoint to make it valid code – otherwise it’s not in the scope of the goto statement – but that doesn’t affect the answer.

    Think about what happens when GetResult throws its exception. We’ll go through the catch block, increment i, and then loop round again (assuming i is still less than 3). We’re still in whatever state we were before the GetResult call… but when we get inside the try block we must print "In Try" and call GetAwaiter again… and we’ll only do that if state isn’t 1. Without the state = 0 assignment, it will use the existing awaiter and skip the Console.WriteLine call.

    It’s a fairly tortuous bit of code to work through, but that just goes to show the kinds of thing that the team has to think about. I’m glad I’m not responsible for implementing this 🙂

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

Yesterday, after about two years we re-deployed our application. Code hasn't changed, but the
Yesterday i gone through some article about EventAggregator, there some shot of code written
Yesterday I've posted question about SQLite performance issues ( Terrible performance in Zend Db
yesterday I took a database exam and the question about normalization was strange. We
I switched from Visual Studio to Code::Blocks yesterday, and just had some strange compiler
Yesterday and for about months I was able to push/commit. But since few hours
Yesterday, I started here asking a question about my own project, and when I
my eclipse galileo installation has started giving me problems all of a sudden. yesterday
Yesterday I asked a question here about a oneliner and mjschultz gave me an
Yesterday , I asked a question about socket post file data to php page.

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.