Reputation: 1833
I was reading about the async pattern in C# in depth, and I decided to take Jon's advice and decompile the async code to actually see what was going on. And I came across two scenarios that confused me a bit as to why they were different.
Consider these two functions:
public static async Task<string> GetValue(){
int count = 0;
count++;
string g = "asdf";
var r = Task.FromResult<string> ("hello");
return g;
}
And
public static async Task<string> GetValue(){
int count = 0;
count++;
string g = "asdf";
var r = await Task.FromResult<string> ("hello");
return g;
}
Now I'd expect the code to ouput the same IL being that they are both async functions so there needs to be a state machine. But to my surprise the C# compiler does create the statemachine in both cases follows all the same code as one would expect, except in the first code block it doesn't actually save any information in the machine. Where in the second it does store all the variables.
Is there a reason that the compiler decides to not save the variables in the state machine and expose two different code paths based on the await
keword?
Upvotes: 0
Views: 126
Reputation: 22122
Only variable, that visible by await
expression need to be captured:
public static async Task Method() {
int a=3;
Console.WriteLine(a);
{
int b=3;
Console.WriteLine(b);
}
await Task.FromResult(true);
}
For example, in code above a
captured, b
not captured. So, if you does not use await
, nothing need to be captured.
Upvotes: 1
Reputation: 11480
I believe the disparity stems from the lack of the await
operator. Without the await
the compiler is treating your code as synchronous code. Which has no reason to utilize the state machine
.
So in essence it creates the state machine
as it expects asynchronous
code, but you do not actually implement any code that is async
. Which keeps it as an empty container.
The setup code initializes the state machine used to represent the asynchronous method and then kicks it off using a call to the secondary MoveNext method on the state machine. This state machine type holds state for the asynchronous method, allowing that state to be persisted across asynchronous await points, if necessary.
The State Machine holds your data in your second example because of the await
. This triggers the State Machine to persist the data through multiple await points
. Since the other example doesn't contain await, it remains empty. It only created the State Machine because you decorated it as async
though it really isn't.
A small excerpt from an article on the matter, hopefully this helps.
Upvotes: 1
Reputation: 273244
The first one should have given you a warning about not really being async ("... will run synchronously") because there is no await
in there.
So there is a state machine because you marked it async
and it could be called with await
.
But there is no information to keep because there is no await
inside the method that would use it.
Upvotes: 2