为什么选择新实例只在枚举上构造?

时间:2016-01-24 12:41:53

标签: c# linq

为什么以下每次循环IEnumerable而不是在初始选择期间创建实例?

this.bars = this.values.Select(x => new Bar(x));

我希望循环遍历这些值,然后在那里选择一个新的Bar,但是经过测试后,它不会在那一刻创建任何实例,而是在每次循环时创建新的实例。

    private IEnumerable<Bar> bars;

bars字段被声明为IEnuermable,所以我不明白它是如何持有任何类型的函数或闭包。

  • 这是预期的行为,如果是这样,为什么?
  • 我如何使用Linq执行此操作,但是然后创建一组新实例?

控制台测试应用的完整来源:

namespace LINQ_Test
{
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq;

    public class Bar
    {
        private int value;

        public Bar(int value)
        {
            this.value = value;
            Debug.WriteLine("CTOR: " + value);
        }
    }

    public class Foo
    {
        private IEnumerable<Bar> bars;
        private IEnumerable<int> values = new int[] { 0, 1234, -1 };

        public void LoopValues()
        {
            Debug.WriteLine("Looping through bars 3 times:");
            for (int loop = 0; loop < 3; loop++)
            {
                foreach (Bar bar in this.bars)
                {
                }
                Debug.WriteLine("   (next loop)");
            }
            Debug.WriteLine("-\n");
        }

        public void SetupValues()
        {
            Debug.WriteLine("Settings up bars:");
            this.bars = this.values.Select(x => new Bar(x));
            Debug.WriteLine("-\n");
        }
    }

    internal class Program
    {
        private static void Main(string[] args)
        {
            Foo foo = new Foo();
            foo.SetupValues();
            foo.LoopValues();
        }
    }
}

App输出:

Settings up bars:
-

Looping through bars 3 times:
CTOR: 0
CTOR: 1234
CTOR: -1
   (next loop)
CTOR: 0
CTOR: 1234
CTOR: -1
   (next loop)
CTOR: 0
CTOR: 1234
CTOR: -1
   (next loop)
-

1 个答案:

答案 0 :(得分:2)

是的,这是预期的行为,并记录在IEnumerable#Select documentation中。从那个链接:

  

此方法通过使用延迟执行来实现。立即返回值是一个对象,它存储执行操作所需的所有信息。直到通过直接调用其GetEnumerator方法或在Visual C#中使用foreach或在Visual Basic中使用For Each来枚举对象时,才会执行此方法表示的查询。

如果您希望立即完成,请立即枚举,可能使用ToList