I am trying to execute an existing synchronous method asynchronously, however if the method is IEnumerable
, then it appears to skip over the method.
Here's a simplified version of what I'm trying to achieve.
public partial class MainWindow : Window
{
private IEnumerable<int> _Result;
public MainWindow()
{
InitializeComponent();
DoSomethingAmazing();
}
private async void DoSomethingAmazing()
{
_Result = await DoSomethingAsync();
}
private IEnumerable<int> DoSomething()
{
Debug.WriteLine("Doing something.");
//Do something crazy and yield return something useful.
yield return 10;
}
private async Task<IEnumerable<int>> DoSomethingAsync()
{
//Perform the DoSomething method asynchronously.
return await Task.Run(() => DoSomething());
}
}
Essentially, when then MainWindow
gets created, it will fire off an asynchronous method to populate the _Result
field.
Now DoSomething
never actually executes. The debug message never appears.
If I change IEnumerable
to List
, then all is well. The method gets executed and the result gets populated.
The main reason I want to use IEnumerable
is because I'd like to make use of yield return
, it's not exactly a requirement, but it's mainly just a preference. I came across this issue and I've been scratching my head ever since.
The result of running the DoSomething
method is a class that implements IEnumerable<int>
and will run your code when you enumerate it. Your problem has nothing to do with using async. If you run the following code
var result = DoSomething();
Debug.WriteLine("After running DoSomething");
var resultAsList = result.ToList();
Debug.WriteLine("After enumerating result");
you will get this output.
After running DoSomething
Doing something.
After enumerating result
Now DoSomething never actually executes. The debug message never appears.
That's because when you use yield return
, the compiler will generate a class which implements IEnumerable<T>
for you, and return the iterator. It looks like this:
Program.<DoSomething>d__3 expr_07 = new Program.<DoSomething>d__3(-2);
expr_07.<>4__this = this;
return expr_07;
Where <DoSomething>d__3
is the compiler generated class, implementing IEnumerable<int>
.
Now, because the iterator uses deferred execution, it doesn't begin execution unless you explicitly iterate it, which you aren't doing.
If I change IEnumerable to List, then all is well. The method gets executed and the result gets populated.
That's because when you use a List
, you're materializing the iterator, effectively making it execute. That's why you're seeing the debug message appear.
Change your DoSomethingAmazing method and it will work.
private async void DoSomethingAmazing()
{
_Result = await DoSomethingAsync();
foreach (var item in _Result)
{
Debug.WriteLine(item);
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.