迭代集合时IEnumerable vs List

时间:2017-04-21 06:13:35

标签: c#

我的问题基本上是一个很好的编程习惯。在IEnumerable的情况下,每个项目在ToList的情况下进行评估,整个集合在开始for循环之前被迭代。 根据下面的代码,应该使用哪个函数(GetBool1 vs GetBool2)以及原因。

public class TestListAndEnumerable1
{
    public static void Test()
    {
        GetBool1();
        GetBool2();

        Console.ReadLine();
    }

    private static void GetBool1()
    {
        var list = new List<int> {0,1,2,3,4,5,6,7,8,9};

        foreach (var item in list.Where(PrintAndEvaluate))
        {
            Thread.Sleep(1000);
        }
    }

    private static bool PrintAndEvaluate(int x)
    {
        Console.WriteLine("Hi from " + x);
        return x%2==0;
    }

    private static void GetBool2()
    {
        List<int> list = new List<int> { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

        foreach (var item in list.Where(PrintAndEvaluate).ToList())
        {
            Thread.Sleep(1000);
        }
    }
}

3 个答案:

答案 0 :(得分:2)

两个循环的bahviour是不同的。在第一种情况下,当每个项目被迭代和评估时,控制台将被写入,并且每个Console.Write之间将发生休眠。

在第二种情况下,还将评估控制台写入,但这些评估将全部发生在休眠之前 - 这些仅在所有PrintAndEvaluate调用完成时发生。

第二种情况枚举列表的成员两次,分配和分段内存,因为它这样做。

如果您的问题是“哪个最有效”,那么答案就是第一个例子,但如果你想知道“还有另一个更有效的方法”,那么就像使用一个循环一样;

  for(int counter = 0 ; counter <= list.Count; counter ++)
    {
        if(PrintAndEvaluate(list[counter]))
        {
           Thread.Sleep(1000);
        }
    }

这可以防止构造Iterator类的实例,因此不会导致堆碎片。

答案 1 :(得分:0)

GetBool1应该被使用。

两种方法之间的唯一区别是ToList()调用的存在。正确?

首先阅读docs来了解ToList来电的重要性:

  

List<T>创建IEnumerable<T>

这意味着当您致电ToList时,系统会创建一个新列表。您可能知道,创建新列表需要时间和内存。

另一方面,GetBool1没有ToList调用,因此执行时间不会太长。

答案 2 :(得分:-1)

GetBool1是更好的选择。对于option2,即使你将IEnumerable转换为List,当你调用foreach时它再次调用GetEnumerator。但差异很小。我对您的代码进行了一些更改以输出执行时间:

 public static void Test()
        {
            var list = new List<int>();
            for (int i = 0; i < 10000; i++)
            {
                list.Add(i);
            }

            GetBool1(list);
            GetBool2(list);
            GetBool3(list);
            Console.ReadLine();
        }

        private static void GetBool1(List<int> list)
        {
            System.Diagnostics.Stopwatch watcher = new System.Diagnostics.Stopwatch();

            watcher.Start();
            foreach (var item in list.Where(PrintAndEvaluate))
            {
                Thread.Sleep(1);
            }
            watcher.Stop();
            Console.WriteLine("GetBool1 - {0}", watcher.ElapsedMilliseconds);
        }

        private static bool PrintAndEvaluate(int x)
        {
            return x % 2 == 0;
        }

        private static void GetBool2(List<int> list)
        {
            System.Diagnostics.Stopwatch watcher = new System.Diagnostics.Stopwatch();

            watcher.Start();
            foreach (var item in list.Where(PrintAndEvaluate).ToList())
            {
                Thread.Sleep(1);
            }
            watcher.Stop();
            Console.WriteLine("GetBool2 - {0}", watcher.ElapsedMilliseconds);
        }

输出是: enter image description here