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