繁体   English   中英

假 if 语句仍然执行

[英]False if-statement still executes

我有以下方法,它应该遍历树,同时在每个节点上调用操作,并且每次在层次结构上向上或向下时调用一次。 逻辑本身完美无缺,但我意识到我的单元测试失败了,因为检查已调用元素的 if 语句无法执行逻辑上的意图。

public static void IterateWithHierarchyFeedback(TBase start,
    Func<TBase, IEnumerable<TBase>> childSelector,
    Action<TBase> invoker,
    Action stepUpInvocator,
    Action stepDownInvocator,
    bool invokeOnStart)
{
    Stack<DynamicIterator> iterationStack = new Stack<DynamicIterator>();
    iterationStack.Push(new DynamicIterator(start, childSelector(start).GetEnumerator()));

    while (iterationStack.Count > 0)
    {
        var current = iterationStack.Pop();
        // HERE it fails because current.Invoked = true but invoker() is still executed
        if (!current.Invoked && invokeOnStart || current.Current != start)
            invoker(current.Current);

        if (current.Enumerator == null || !current.Enumerator.MoveNext())
        {
            if (current.Current != start)
                stepUpInvocator();
            continue;
        }

        stepDownInvocator();

        current.Invoked = true;
        iterationStack.Push(current);
        iterationStack.Push(new DynamicIterator(current.Enumerator.Current,
            childSelector(current.Enumerator.Current)?.GetEnumerator()));
        continue;
    }
}

这是我的单元测试:

[测试] 公共异步任务 TestIterateWithFeedback() { StringBuilder b = new StringBuilder();

DynamicIterate<Tree>.Downwards.IterateWithHierarchyFeedback(_tree, t => t.Children,
    tree => b.Append(tree.ReturnValue.ToString()),
    () => b.Append('<'),
    () => b.Append('>'),
    true);

Assert.Warn(b.ToString());
const string expected = "1>2>3>4<>5<<>6<<>7>>";
Assert.AreEqual(expected, b.ToString());

}

在这里你看到输出不是它应该的样子。 那是因为invoker()是在已经被调用的元素上调用的,否则在排序时输出将是正确的:

  2)   Expected string length 20 but was 23. Strings differ at index 8.
  Expected: "1>2>3>4<>5<<>6<<>7>>"
  But was:  "1>2>3>4<3>5<3<2>6<2<>7<"

谁能向我解释为什么会发生这种情况? 我发现了这一点,但即使没有调试器,它也会发生。 我还尝试将我的状态对象( DynamicIterator )从 struct 更改为 class (因为我最初认为这可能是异步变体的问题。但这也没有改变任何东西。

我不确定问题是什么,但迭代代码看起来比需要的更复杂。 我会提出这样的建议:

    public static IEnumerable<(T Node, int Level)> DepthFirstWithlevel<T>(
           T self, 
           Func<T, IEnumerable<T>> selector)
    {
        var stack = new Stack<(T Node, int Level)>();
        stack.Push((self, 0));
        while (stack.Count > 0)
        {
            var current = stack.Pop();
            yield return current;
            foreach (var child in selector(current.Node))
            {
                stack.Push((child, current.Level + 1));
            }
        }
    }

这将返回树中的每个节点,以及该节点在树中的级别,0 是根。 如果您特别需要为每个级别更改调用方法,您可以使用单独的方法来实现,如下所示:

    public static void IterateWithHierarchyFeedback<T>(
        T self, 
        Func<T, IEnumerable<T>> selector, 
        Action<T> invoker, 
        Action stepUp, 
        Action stepDown)
    {
        int currentLevel = 0;
        foreach (var (node, level) in DepthFirstWithLevel(self, selector))
        {
            while (currentLevel < level)
            {
                currentLevel++;
                stepDown();
            }

            while (currentLevel > level)
            {
                currentLevel--;
                stepUp();
            }

            invoker(node);
        }
    }

为树

A - B - C
  |  ⌞ D
   ⌞E - F

它将打印A>E>F<B>DC ,即它将首先遍历底部分支.Reverse()selector(current.Node)之后插入一个.Reverse() selector(current.Node)来改变它)。 它将直接从 F 转到 B,而无需重新访问 A。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM