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. 使用结构是类似于 BCLList<T>.Enumerator结构的性能增益,如本答案所述,并且
  2. 如 Eric Lippert 的博客所述,该结构没有实现IDisposable,因此不必担心这样做可能会产生错误。

但是,与 BCLList<T>类不同的是,它有一个嵌套EnumeratorImpl类。这是为了

  1. 避免使用一次性结构,并且
  2. 避免在显式实现IEnumerable<SyntaxNodeOrToken>.GetEnumeratorIEnumerable.GetEnumerator方法中装箱?

还有其他原因吗?

4

1 回答 1

20

还有其他原因吗?

一个都没有想到。您似乎已经准确地描述了序列模式的这种相当奇怪的实现的目的。

我赶紧补充一下:Roslyn 是一个不同寻常的 .NET 应用程序,它的复杂性、性能要求以及它生成的对象数量都是如此。一个编译器在用户键入时分析包含数千个文件、数百万行和数千万字符的程序,必须做一些非常不寻常的事情,以确保它不会压倒垃圾收集器。因此,Roslyn 使用池化策略、可变值类型和其他非主流实践来帮助实现这些性能目标。我不建议承担与这些做法相关的费用和困难,除非您有经验证据确定这些做法可以缓解的严重性能问题. 仅仅因为这段代码是由 C# 编译器团队编写的,并不意味着这是编写主流业务对象的黄金标准。

于 2013-09-11T17:19:42.737 回答