等待任务不适用于 IEnumerable

await Task doesn't work with IEnumerable

我正在尝试异步执行现有的同步方法,但是如果该方法是 IEnumerable,那么它似乎会跳过该方法。

这是我要实现的目标的简化版本。

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());
    }
}

本质上,当创建 MainWindow 时,它将触发一个异步方法来填充 _Result 字段。

现在 DoSomething 从未真正执行过。调试消息从未出现。

如果我把IEnumerable改成List,那就没问题了。该方法得到执行,结果得到填充。

我想使用 IEnumerable 的主要原因是因为我想使用 yield return,这不完全是一个要求,但它主要只是一个偏好。我遇到了这个问题,从那以后我一直在摸不着头脑。

更改您的 DoSomethingAmazing 方法,它将起作用。

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

运行使用 DoSomething 方法的结果是一个 class,它实现了 IEnumerable<int> 并且在您枚举代码时将 运行 您的代码。您的问题与使用异步无关。如果你运行下面的代码

var result = DoSomething();
Debug.WriteLine("After running DoSomething");
var resultAsList = result.ToList();
Debug.WriteLine("After enumerating result");

你会得到这个输出。

After running DoSomething

Doing something.

After enumerating result

Now DoSomething never actually executes. The debug message never appears.

那是因为当你使用yield return时,编译器会生成一个class为你实现IEnumerable<T>,return是迭代器。它看起来像这样:

Program.<DoSomething>d__3 expr_07 = new Program.<DoSomething>d__3(-2);
expr_07.<>4__this = this;
return expr_07;

其中 <DoSomething>d__3 是编译器生成的 class,实现 IEnumerable<int>.

现在,因为迭代器使用延迟执行,它不会开始执行,除非您显式迭代它,而您并没有这样做。

If I change IEnumerable to List, then all is well. The method gets executed and the result gets populated.

那是因为当您使用 List 时,您正在具体化迭代器,有效地使其执行。这就是您看到出现调试消息的原因。