簡體   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