我的问题基本上是一个很好的编程习惯。在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);
}
}
}
答案 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);
}