StrongBox的一个特殊用法

时间:2014-01-21 16:27:43

标签: roslyn

我正在查看带有Reflector的Roslyn September 2012 CTP,我注意到语法树的以下深度优先遍历:

private IEnumerable<CommonSyntaxNode> DescendantNodesOnly(TextSpan span,
    Func<CommonSyntaxNode, bool> descendIntoChildren, bool includeSelf)
{
    if (includeSelf && IsInSpan(span, FullSpan))
    {
        yield return this;
    }

    if ((descendIntoChildren != null) && !descendIntoChildren(this))
    {
        yield break;
    }

    var queue = new Queue<StrongBox<IEnumerator<CommonSyntaxNode>>>();
    var stack = new Stack<StrongBox<IEnumerator<CommonSyntaxNode>>>();
    stack.Push(new StrongBox<IEnumerator<CommonSyntaxNode>>(ChildNodes().GetEnumerator()));
    while (stack.Count > 0)
    {
        var enumerator = stack.Peek();
        StrongBox<IEnumerator<CommonSyntaxNode>> childEnumerator;
        if (enumerator.Value.MoveNext())
        {
            var current = enumerator.Value.Current;
            if (IsInSpan(span, current.FullSpan))
            {
                yield return current;

                if ((descendIntoChildren == null) || descendIntoChildren(current))
                {
                    childEnumerator = queue.Count == 0
                        ? new StrongBox<IEnumerator<CommonSyntaxNode>>()
                        : queue.Dequeue();
                    childEnumerator.Value = current.ChildNodes().GetEnumerator();
                    stack.Push(childEnumerator);
                }
            }
        }
        else
        {
            childEnumerator = stack.Pop();
            childEnumerator.Value = null;
            queue.Enqueue(childEnumerator);
        }
    }
}

我猜这个队列是为了简化运行时分配和解除分配IEnumerator<CommonSyntaxNode>的这么多实例。

但是,我不确定为什么IEnumerator<CommonSyntaxNode>包含在StrongBox<>中。在引用类型IEnumerator<CommonSyntaxNode>中包装StrongBox<>(通常是值类型)涉及哪种性能和安全权衡?

3 个答案:

答案 0 :(得分:3)

CommonSyntaxNode是一个抽象类,它包含很多值类型,可以继承到一个大对象中。

IEnumerator<CommonSyntaxNode>仅包含对CommonSyntaxNode的引用,因此CommonSyntaxNode的大小似乎不会影响Enumerator大小,因为它只是一个参考,< EM>但:

因为 IEnumerator<T> 的方法 MoveNext() 使用yield return; Enumerator中的每次迭代都会导致该方法保存它的状态,直到下一次迭代。

因为整个方法状态足够重,并且它可能包含CommonSyntaxNode的属性以执行 MoveNext() 逻辑,而不是整个IEnumerator<CommonSyntaxNode>记忆可能会非常沉重。

使用 StrongBox<> 会导致QueueStack只保留一个小的引用对象(StrongBox<>而不是内存中可能很重的{ {1}} - 因此 - GC正在更快地清除内存中包含IEnumerator<CommonSyntaxNode>Queue StackIEnumerator<CommonSyntaxNode> - 减少应用程序的总内存消耗。

请注意CommonSyntaxNode的枚举器是一个结构,使用它直接意味着深度复制整个结构,它是一个小结构,所以它不是很重,但仍然...

答案 1 :(得分:3)

StrongBox<T>的优点是,一旦项目出列,StrongBox就会清除它的内部内容 - 因此GC可以收集StrongBox持有的T实例,Queue<T>结束只持有StrongBox的一个实例(而不是T的实例)。

答案 2 :(得分:0)

使用IEnumerator是一个错误。代码应该使用ChildSyntaxList.Enumerator,它是一个结构。 StrongBox的使用是针对性能,以防止需要推送和当它们发生变化时,从堆栈末尾弹出枚举器。