为什么需要 Enumerator 结构体和 EnumeratorImpl 类?

5

我正在使用Reflector查看Roslyn 2012年9月CTP,并注意到ChildSyntaxList结构具有以下内容:

public struct ChildSyntaxList : IEnumerable<SyntaxNodeOrToken>
{
    private readonly SyntaxNode node;
    private readonly int count;

    public Enumerator GetEnumerator()
    {
        return node == null ? new Enumerator() : new Enumerator(node, count);
    }

    IEnumerator<SyntaxNodeOrToken> IEnumerable<SyntaxNodeOrToken>.GetEnumerator()
    {
        return node == null
            ? SpecializedCollections.EmptyEnumerator<SyntaxNodeOrToken>()
            : new EnumeratorImpl(node, count);
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return node == null
            ? SpecializedCollections.EmptyEnumerator<SyntaxNodeOrToken>()
            : new EnumeratorImpl(node, count);
    }

    public struct Enumerator
    {
        internal Enumerator(SyntaxNode node, int count)
        {
            /* logic */
        }

        public SyntaxNodeOrToken Current { get { /* logic */ } }

        public bool MoveNext()
        {
            /* logic */
        }

        public void Reset()
        {
            /* logic */
        }
    }

    private class EnumeratorImpl : IEnumerator<SyntaxNodeOrToken>
    {
        private Enumerator enumerator;

        internal EnumeratorImpl(SyntaxNode node, int count)
        {
            enumerator = new Enumerator(node, count);
        }

        public SyntaxNodeOrToken Current { get { return enumerator.Current; } }

        object IEnumerator.Current { get { return enumerator.Current; } }

        public void Dispose()
        {
        }

        public bool MoveNext()
        {
            return enumerator.MoveNext();
        }

        public void Reset()
        {
            enumerator.Reset();
        }
    }
}

也就是说,有一个GetEnumerator方法返回一个结构体。

看起来像这样

  1. 使用结构体类似于BCL List<T>.Enumerator结构体的性能提升,如在此答案中所述, 以及
  2. 该结构体不实现IDisposable,以免担心可能会出现的错误,如Eric Lippert的博客上所述

然而,与BCL List<T>类不同的是,这里有一个嵌套的EnumeratorImpl类。它的目的是

  1. 避免使用可处理的结构体,并且
  2. 避免在明确实现的IEnumerable<SyntaxNodeOrToken>.GetEnumeratorIEnumerable.GetEnumerator方法中进行装箱吗?

还有其他原因吗?

1个回答

21

还有其他的原因吗?

我想不出其他的原因了。你似乎准确地描述了这种奇怪的序列模式实现的目的。

我要赶紧补充一点:Roslyn是一个复杂的.NET应用程序,它具有高性能要求和大量生成对象的特点。编译器在用户输入时分析数千个文件、数百万行和数千万个字符的程序必须采取一些非常不寻常的措施,以确保不会压垮垃圾回收器。因此,Roslyn使用池化策略、可变值类型和其他非主流实践来帮助实现这些性能目标。除非您有经验证明这些实践可以缓解严重的性能问题,否则我不建议采用这些实践所需的成本和难度。仅仅因为这段代码是由C#编译器团队编写的,并不意味着这是编写主流业务对象的金标准。


我同意,除非有经验证据表明这些优化是必要的,否则您不会进行这些优化,因为它们具有开发和维护成本。但是,如果这些优化是免费的呢?如果某个代码生成器或编译器可以为您执行这些优化,那么您就不必输入它们或阅读它们了吗?是否有证据表明Roslyn编译器是使用这样的代码生成器或重写器编写的,甚至Roslyn编译器正在对自身进行这些优化?两者都是可能的... - Kris Vandermotten

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接