[英]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.