等待任务不适用于IEnumerable

时间:2015-07-23 13:10:11

标签: c# asynchronous async-await task

我正在尝试异步执行现有的同步方法,但是如果方法是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,这不是一个要求,但它主要是只是一个偏好。我遇到过这个问题,从那时起我一直在挠头。

3 个答案:

答案 0 :(得分:3)

运行IEnumerable<int>方法的结果是一个实现var result = DoSomething(); Debug.WriteLine("After running DoSomething"); var resultAsList = result.ToList(); Debug.WriteLine("After enumerating result"); 的类,并在枚举时运行代码。您的问题与使用异步无关。如果您运行以下代码

animate

你会得到这个输出。

  

运行DoSomething后

     

做点什么。

     

枚举结果后

答案 1 :(得分:2)

  

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

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

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

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

现在,因为迭代器使用延迟执行,所以除非你明确地迭代它,否则它不会开始执行,你不会这样做。

  

如果我将IEnumerable更改为List,那么一切都很好。方法得到   执行并结果填充。

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

答案 2 :(得分:0)

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

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