优化LINQ的IList的LINQ、IList

由网友(ヾ誓言只是謊言的代名詞)分享简介:前一段时间我写了的IList 扩展方法,通过使用索引整个列表的一部分枚举。虽然重构我实现了一个类似的查询可以通过调用执行跳过(toSkip)。取(量)。虽然这个基准测试,我注意到跳不为的IList 优化。带着几分谷歌搜索的,我结束了在乔恩斯基特后,讨论为什么优化方法,如跳过是危险。A while ago I wrot...

前一段时间我写了的IList 扩展方法,通过使用索引整个列表的一部分枚举。虽然重构我实现了一个类似的查询可以通过调用执行跳过(toSkip)。取(量)。虽然这个基准测试,我注意到不为的IList 优化。带着几分谷歌搜索的,我结束了在乔恩斯基特后,讨论为什么优化方法,如跳过是危险。

A while ago I wrote an IList extension method to enumerate across part of a list by using the indices. While refactoring I realized a similar query could be performed by calling Skip(toSkip).Take(amount). While benchmarking this I noticed that Skip isn't optimized for IList. With a bit of googling I ended up at a Jon Skeet post, discussing why optimizing methods like Skip is dangerous.

据我理解文章,问题是不会抛出异常的优化方法,当集合被修改,但作为一个注释状态MSDN文档冲突本身。

As far as I understand the article, the problem is no exception is thrown in the optimized methods when the collection is modified, but as a comment states the msdn documentation conflicts itself.

在 IEnumerator.MoveNext()

如果更改了收集,   例如添加,修改或删除   元素,枚举是   失效且不可恢复,并且下一个   呼吁对MoveNext或Reset 引发   InvalidOperationException异常。

If changes are made to the collection, such as adding, modifying, or deleting elements, the enumerator is irrecoverably invalidated and the next call to MoveNext or Reset throws an InvalidOperationException.

在 IEnumerator.GetEnumerator():

如果更改了收集,   例如添加,修改或删除   元素,枚举是   失效且不可恢复,其   行为的未定义

If changes are made to the collection, such as adding, modifying, or deleting elements, the enumerator is irrecoverably invalidated and its behavior is undefined.

我看在这两个公约的优点,并感到有点失落是否要优化。什么是一个妥善的解决办法?我一直在考虑沿的行的 IList.AssumeImmutable()办法进行AsParallel()所提到的克里斯Vandermotten在意见。是否有实施已经存在,或者是一个坏主意?

I see merit in both conventions, and am a bit lost whether or not to optimize. What is a proper solution? I've been considering an IList.AssumeImmutable() approach along the lines of AsParallel() as mentioned by Kris Vandermotten in the comments. Does any implementation already exist, or is it a bad idea?

推荐答案

我同意雷夫的未定义行为是比较正确的。只有版本的集合可以抛出异常,而不是所有的集合版本(数组是最大的例子)。如果你拨打电话的正是2 ^ 32变为的MoveNext 即使版本集可能会表现不好。

I agree with Rafe that the undefined behavior is more correct. Only versioned collections can throw exceptions and not all collections are versioned (arrays being the largest example). Even versioned collections might misbehave if you make exactly 2^32 changes between calls to MoveNext.

假设你真正关心的版本问题,解决的办法是让一个枚举的IList 和呼叫的MoveNext 于它的每次迭代:

Assuming you really care about the versioning behavior, the solution is to get an Enumerator for the IList and call MoveNext on it for every iteration:

    public static IEnumerable<T> Skip<T>(this IList<T> source, int count)
    {
        using (var e = source.GetEnumerator())
            while (count < source.Count && e.MoveNext())
                yield return source[count++];
    }

这样你得到的O(1)行为通过索引,但你仍然可以调用所有的异常抛出的行为的MoveNext 。需要注意的是,我们只调用的MoveNext 为异常的副作用;我们忽略了它的枚举所有的值。

This way you get O(1) behavior by indexing, but you still get all the exception throwing behavior of calling MoveNext. Note that we only call MoveNext for the exception side-effects; we ignore the values that it's enumerating over.

阅读全文

相关推荐

最新文章