有没有办法记住或物化IEnumerable?

当给定d您可能正在处理类似列表或数组的固定序列,将枚举某些外部数据源的AST,甚至是某些现有集合上的AST。 有没有办法安全地“实现”枚举,以便像foreach,count等枚举操作每次都不执行AST?

我经常使用.ToArray()来创建这个表示,但如果底层存储已经是一个列表或其他固定序列,那似乎就是浪费了复制。 如果我能这样做会很好

 var enumerable = someEnumerable.Materialize(); if(enumberable.Any() { foreach(var item in enumerable) { ... } } else { ... } 

不必担心.Any()foreach尝试枚举序列两次,没有它不成功地复制可枚举。

很容易:

 public static IList Materialize(this IEnumerable source) { if (source is IList) { // Already a list, use it as is return (IList)source; } else { // Not a list, materialize it to a list return source.ToList(); } } 

和托马斯的回答一样,根据我的说法,这个问题要好一点:

 public static ICollection Materialize(this IEnumerable source) { if (source == null) return null; return source as ICollection ?? source.ToList(); } 

请注意,如果它是有效的集合类型,则往往会返回现有集合本身,否则会生成新集合。 虽然两者略有不同,但我认为这不是一个问题。

看看我几年前写的这篇博文: http : //www.fallingcanbedeadly.com/posts/crazy-extention-methods-tolazylist

在其中,我定义了一个名为ToLazyList的方法,可以有效地完成您正在寻找的内容。

如上所述,它最终会生成输入序列的完整副本,尽管您可以对其进行调整,以便IList的实例不会被包装在LazyList中,这样可以防止这种情况发生(但是,此操作会随之发生)你得到的任何IList的假设已经被有效地记忆了)。