C# 为IList优化LINQ

C# 为IList优化LINQ,c#,.net,linq,optimization,skip,C#,.net,Linq,Optimization,Skip,不久前,我编写了一个IList扩展方法,通过使用索引跨列表的一部分进行枚举。在重构过程中,我意识到可以通过调用Skip(toSkip).Take(amount)执行类似的查询。在对此进行基准测试时,我注意到Skip并没有针对IList进行优化。通过一点谷歌搜索,我最终在Jon Skeet的一家邮局工作 就我对这篇文章的理解而言,问题在于当修改集合时,优化方法中没有引发异常,但正如注释所述,msdn文档本身存在冲突 在: 如果对集合进行了更改, 例如添加、修改或删除 元素,枚举数为 无法恢复的无效

不久前,我编写了一个
IList
扩展方法,通过使用索引跨列表的一部分进行枚举。在重构过程中,我意识到可以通过调用
Skip(toSkip).Take(amount)
执行类似的查询。在对此进行基准测试时,我注意到
Skip
并没有针对
IList
进行优化。通过一点谷歌搜索,我最终在Jon Skeet的一家邮局工作

就我对这篇文章的理解而言,问题在于当修改集合时,优化方法中没有引发异常,但正如注释所述,msdn文档本身存在冲突

在:

如果对集合进行了更改, 例如添加、修改或删除 元素,枚举数为 无法恢复的无效和下一个 调用MoveNext或Reset会抛出 无效操作异常。

在:

如果对集合进行了更改, 例如添加、修改或删除 元素,枚举数为 不可恢复的无效及其后果 行为未定义

我看到了这两种约定的优点,对于是否进行优化,我有点不知所措。什么是正确的解决方案?我一直在考虑一种
IList.AssumeImmutable()
方法,就像Kris Vandermotten在评论中提到的那样。是否已经存在任何实现,或者这是一个坏主意?

该类可能有助于处理不可变集合

我的建议:我个人不会试图“欺骗”编译器,除非你有性能问题。你永远不知道,下一个版本可能会使优化代码的运行速度比原来的慢一倍。不要先发制人地优化。框架中提供的方法可以生成一些真正优化的代码,这些代码很难重新实现


是一篇来自msdn的文章,提供了用于不同目的的集合的信息。我会为任务使用适当的集合,而不是尝试优化Skip and Take。

我同意Rafe的观点,即未定义的行为更正确。只有已版本化的集合可以引发异常,并且并非所有集合都已版本化(数组是最大的示例)。如果在调用
MoveNext
之间进行2^32次更改,则即使是版本化的集合也可能会出现错误

假设您真的关心版本控制行为,解决方案是为
IList
获取一个
枚举器,并为每次迭代调用
MoveNext

    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++];
    }
公共静态IEnumerable Skip(此IList源,int count)
{
使用(var e=source.GetEnumerator())
while(count

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

如果Jon得出结论,优化
跳过
等将是一个错误,并且有一段解释为什么。。。我认为“undefined”语义比“throwseanexception”语义更实用(尽管后者更可靠),仅仅因为后者要求每个枚举器实例都能够测试对宿主容器的修改。啊!然而,乔恩的观点仍然站得住脚。没有任何东西可以阻止您在不使用
Skip/Take
@Rafe的情况下编写
ItemsInRange(Lo,Hi)
枚举器:我写了一个这样的答案并删除了它,因为根据对称性
ItemsInRange
也应该存在于
IEnumerable
中,并且会抛出,因此,
IList
版本无法通过Jon的论点进行优化。@Marc:我们怎么知道Jon在重新思考时是正确的,而在一开始就不正确?我不理解你的答案与这个问题的关系。“问题是,执行的下一行代码可能不是调用MoveNext()想澄清一下吗?@Steven-并不是想发布第一段。我开始回答,以为你在问别的问题。我已经更新了它以删除该文本。我真的需要在睡觉前停止回答问题。有趣的解决方案!它看起来有点像黑客,但实际上是有道理的。