当给定一个d
时,你可以处理一个固定的序列,比如一个列表或数组,一个将枚举一些外部数据源的AST,甚至是一个现有集合上的AST。有没有一种方法可以安全地“具体化”可枚举对象,这样foreach,count等枚举操作就不会每次都执行AST?
我经常使用.ToArray()
来创建这种表示,但如果底层存储已经是一个列表或其他固定序列,那似乎是浪费复制。
var enumerable = someEnumerable.Materialize();
if(enumberable.Any() {
foreach(var item in enumerable) {
...
}
} else {
...
}
不必担心.Any()
和foreach
尝试枚举序列两次,并且不会不必要地复制可枚举对象。
3条答案
按热度按时间6ioyuze21#
很简单:
5ssjco0h2#
原始答案:
和托马斯的答案一样,只是我觉得更好一点:
请注意,如果集合类型是有效的,则返回现有集合本身,否则会生成一个新集合。虽然两者有细微的不同,但我不认为这是一个问题。
编辑:
现在,这是一个更好的解决方案:
请注意,上面的解决方案忽略了一个特定的协变情况,即集合类型实现了
ICollection<T>
,但没有实现IReadOnlyCollection<T>
。例如,假设您有一个如下的集合:上面的编译是因为
IEnumerable<T>
是协变的。上面的代码创建了一个
new List<Random>
(O(N)),即使我们传递了一个已经物化的集合。原因是ICollection<T>
不是协变接口(它不可能是),因此我们从Collection<Random>
到ICollection<object>
的转换失败,因此执行switch中的default:
case。我相信集合类型实现
ICollection<T>
而不实现IReadOnlyCollection<T>
是极其罕见的情况。我将忽略这种情况。扫描BCL库时,我只能找到很少的几个,而且几乎没有听说过。如果您还需要涵盖这种情况,您可以使用一些反射。类似于:gjmwrych3#
看看我几年前写的这篇博客:http://www.fallingcanbedeadly.com/posts/crazy-extention-methods-tolazylist
在其中,我定义了一个名为ToLazyList的方法,它可以有效地完成您所需要的任务。
正如所写的那样,它最终将生成输入序列的完整副本,尽管您可以对其进行调整,以便IList的示例不会被 Package 在LazyList中,这将防止这种情况发生(但是,此操作将假设您获得的任何IList都已经有效地记忆)。