当给定d
时,您可能正在处理一个固定序列,如列表或数组,AST将枚举一些外部数据源,甚至是某些现有集合上的AST。有没有办法安全地“实现”枚举,以便像foreach,count等枚举操作每次都不执行AST?
我经常使用.ToArray()
创建此表示,但如果底层存储已经是列表或其他固定序列,那么这似乎是浪费复制。如果我能做的话会很好
var enumerable = someEnumerable.Materialize();
if(enumberable.Any() {
foreach(var item in enumerable) {
...
}
} else {
...
}
不必担心.Any()
和foreach
尝试枚举序列两次而不会不成功地复制可枚举。
答案 0 :(得分:6)
足够简单:
public static IList<TSource> Materialize<TSource>(this IEnumerable<TSource> source)
{
if (source is IList<TSource>)
{
// Already a list, use it as is
return (IList<TSource>)source;
}
else
{
// Not a list, materialize it to a list
return source.ToList();
}
}
答案 1 :(得分:6)
与托马斯的答案相同,根据我的说法好一点:
public static ICollection<T> Materialize<T>(this IEnumerable<T> source)
{
if (source == null)
return null;
return source as ICollection<T> ?? source.ToList();
}
请注意,如果它是有效的集合类型,则会倾向于返回现有集合本身,否则会生成新集合。虽然两者略有不同,但我认为这不是一个问题。
答案 2 :(得分:3)
查看我几年前撰写的这篇博文:http://www.fallingcanbedeadly.com/posts/crazy-extention-methods-tolazylist
在其中,我定义了一个名为ToLazyList的方法,可以有效地完成您正在寻找的内容。
正如所写的那样,它最终会生成输入序列的完整副本,尽管你可以调整它以便IList的实例不会被包装在LazyList中,这会阻止这种情况发生(但是,这个动作会随身携带的假设是你得到的任何IList都已经被有效地记忆了。)