简体   繁体   English

等待任务不适用于IEnumerable

[英]await Task doesn't work with IEnumerable

I am trying to execute an existing synchronous method asynchronously, however if the method is IEnumerable , then it appears to skip over the method. 我正在尝试异步执行现有的同步方法,但是,如果该方法是IEnumerable ,那么它似乎会跳过该方法。

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. 本质上,创建MainWindow时,它将触发异步方法来填充_Result字段。

Now DoSomething never actually executes. 现在, DoSomething从未真正执行过。 The debug message never appears. 调试消息永远不会出现。

If I change IEnumerable to List , then all is well. 如果我将IEnumerable更改为List ,那么一切都很好。 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. 我想使用IEnumerable主要原因是因为我想利用yield return ,它并不是完全必要,但主要只是一个首选项。 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. 运行DoSomething方法的结果是一个实现IEnumerable<int>的类,并在枚举它时运行您的代码。 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 运行DoSomething之后

Doing something. 做某事。

After enumerating result 枚举结果后

Now DoSomething never actually executes. 现在,DoSomething从未真正执行过。 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. 这是因为当您使用yield return ,编译器将生成一个为您实现IEnumerable<T>的类,并返回迭代器。 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> . 其中<DoSomething>d__3是编译器生成的类,实现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. 如果我将IEnumerable更改为List,那么一切都很好。 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. 这是因为当您使用List ,您正在实现迭代器,从而有效地使其执行。 That's why you're seeing the debug message appear. 这就是为什么您会看到调试消息的原因。

Change your DoSomethingAmazing method and it will work. 更改您的DoSomethingAmazing方法,它将起作用。

    private async void DoSomethingAmazing()
    {
        _Result = await DoSomethingAsync();
        foreach (var item in _Result)
        {
            Debug.WriteLine(item);
        }
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM