考虑以下代码块:
using (FileStream fs = new FileStream(@"C:\bad_records.txt",
FileMode.Create,
FileAccess.Write))
{
var badEnumerable = _cache.Where(kvp => !kvp.Value.Item1);
fs.WriteLine(string.Format("BAD RECORDS ({0})", badEnumerable.Count()));
fs.WriteLine("==========");
foreach (var item in badEnumerable)
{
fs.WriteLine(string.Format("{0}: {1}", item.Key, item.Value.Item2));
}
}
其中_cache
的定义如下:
static Dictionary<string, Tuple<bool, string, string>> _cache;
我是否将此枚举重复两次?一次使用Count()
一次使用foreach
?
答案 0 :(得分:8)
是的,你正在迭代可枚举两次。
测试此方法的一种简单方法是使用辅助方法,例如:
private static int count = 0;
public static IEnumerable<T> CountIterations<T>(IEnumerable<T> sequence)
{
count++;
//or some other debug type logging
Console.WriteLine("Iterated {0} times.", count);
foreach(var item in sequence)
yield return item;
}
答案 1 :(得分:3)
您将字典_cache
用作IEnumerable
的{{1}}
方法推迟执行的方法
因此,您需要对其进行两次枚举:KeyValuePair
和Count
。
您可以将其更改为:
foreach
和var badEnumerable = _cache.Where(kvp => !kvp.Value.Item1).ToArray();
。
答案 2 :(得分:2)
是的,.Count()
和foreach
都会导致_cache
枚举两次,并根据Where
原因中的谓词进行验证。
关于这是否是一个问题取决于许多事情:
_cache
中的所有值是否已经存在,或者是否正在查询基础源(如数据库)。例如,如果_cache
中的值已经在内存中并且谓词是一个简单的布尔属性比较,那么枚举缓存两次可能更有效并且不会增加额外的内存开销,而添加{{1}仍然会产生2个枚举(.ToList()
之一和列表中的一个)但是谓词检查只会发生一次(在_cache
调用中)并且.ToList()
将有更少的对象枚举,但你会增加附加列表的额外内存开销。
如果缓存来自数据库,则在foreach
之后添加.ToList()
的内存开销几乎肯定会比对数据库执行2次单独查询更好。
答案 3 :(得分:1)
简短的回答是肯定的。
根据badEnumerable
的基础类型,可能枚举两次。这是由于所谓的“deferred execution”。延迟执行意味着您的LINQ查询实际上并未执行“直到查询变量在foreach或For Each循环中迭代”(MSDN)。您的foreach
语句显然是对变量的迭代,Enumerable.Count()
也执行迭代(在本例中)。
但在某些情况下,这不会导致两次迭代。这发生在badEnumerable
is actually a subclass of ICollection
时。在这种情况下,调用.Count()
实际上引用了基础.Count
属性,并且不枚举它。
由于badEnumerable
是Dictionary<TKey, TValue>
,并且因为对Enumerable.Where()
的调用会返回通用IEnumerable
(不是ICollection
),特定情况不会遇到这种情况,并会迭代两次。
答案 4 :(得分:0)
是的,为避免重复两次,请使用List
您可以在初始迭代后打印计数。
另一种解决方案是保存循环中写入的文本,并在打印计数后将其打印出来。
编辑更正:
using (FileStream fs = new FileStream(@"C:\bad_records.txt", FileMode.Create, FileAccess.Write))
{
var badEnumerable = _cache.Where(kvp => !kvp.Value.Item1);
int count = 0;
foreach (var item in badEnumerable)
{
count++;
Console.WriteLine(string.Format("{0}: {1}", item.Key, item.Value.Item2));
}
Console.WriteLine("==========");
Console.WriteLine(string.Format("BAD RECORDS ({0})", count));
}