我有以下递归代码,我得到一个stackoverflow异常。我无法弄清楚根本原因,因为一旦我得到异常,我就不会在Visual Studio中获得完整的调用堆栈。
这个想法是有组织团队加入更大的“主要”团队。
有没有人看到下面这段代码的缺陷可能是罪魁祸首?
private Unit GetUnit(Unit organisationalUnit)
{
if (organisationalUnit.IsMainUnit)
{
return organisationalUnit;
}
if (organisationalUnit.Parent == null)
return null;
return GetUnit(organisationalUnit.Parent);
}
答案 0 :(得分:5)
IsMainUnit
和Parent
的getter不会调用GetUnit
。答案 1 :(得分:4)
根始终有Parent == null
吗?
试过检查
if (organisationalUnit.Parent == organisationalUnit)
return null;
答案 2 :(得分:2)
你可以尝试这个来更好地调试它。它不会影响您的生产代码。
using System.Diagnostics;
private Unit GetUnit(Unit organisationalUnit, int depth)
{
debug.assert(depth < 10, "Reached an unexpected high recursion depth");
if (organisationalUnit.IsMainUnit)
{
return organisationalUnit;
}
if (organisationalUnit.Parent == null)
return null;
return GetUnit(organisationalUnit.Parent, depth + 1);
}
private Unit GetUnit(Unit organisationalUnit)
{
return GetUnit(organisationalUnit.Parent, 0);
}
第二个想法......
最有可能的是你在某个地方有一个循环引用。
A.parent = B;
B.parent = C;
C.parent = A;
您可以尝试传递一组以前访问过的节点,并检查您之前是否访问过该节点。
递归的是必须确定它将结束,并且未经检查的循环引用是不会结束的情况。
答案 3 :(得分:1)
有没有理由不将其重新编码为迭代?这样,为了捕获不良(循环)数据,更容易对组织树的深度设置硬限制。
递归很有趣,尾部优化甚至可以使它高效,但在这里它看起来像一个小问题的大锤子。
答案 4 :(得分:1)
我对视觉工作室了解不多。 但你应该检查是否复发。 e.g。
private Unit GetUnit(Unit organisationalUnit)
{
GetUnit(organisationalUnit, new vector());
}
private Unit GetUnit(Unit organisationalUnit,vector x)
{
if (organisationalUnit.IsMainUnit)
{
return organisationalUnit;
}
if (organisationalUnit.Parent == null)
return null;
x.add(this);
if(x.contains(organisationalUnit.Parent)) throw new Exception("recurrent parent");
return GetUnit(organisationalUnit.Parent,x);
}
答案 5 :(得分:1)
这样做的一种方法是减少堆栈大小,以便它可以更早崩溃。
你可以通过在程序开头浪费帧来做到这一点,即得到如下的堆栈跟踪:f_n,f_(n-1),...,f_1,waste,waste ,...,废物,如(在C伪代码中)
int wasted = 1;
废物(int n,void(* f)()) {if(n> 0)waste(n - 1,f)else f(); 浪费+ = 1; }
main(){waste(N,mainprime); }
其中mainprime是您的旧主页,N足够大,可以达到您想要的f_1。
答案 6 :(得分:0)
代码看起来不错,也许你在单元树中有一些封闭的循环?尝试使用organisationalUnit.GetHashCode值添加跟踪线,跟踪输出不受限制,可以帮助检测堆栈溢出原因。
答案 7 :(得分:0)
我猜你可以通过重写
来避免递归while(organisationalUnit!=null && !organisationalUnit.IsMainUnit)
organisationalUnit=organisationalUnit.Parent;
return organisationalUnit;
我希望有所帮助。
编辑:我刚刚意识到,如果你有某种循环依赖,这仍然会失败。答案 8 :(得分:0)
你的图表中可能有一个循环(参见,它不是树)。
您可以使用这样的代码来检测它:
private Unit GetUnit(Unit organisationalUnit) {
return GetUnit(organisationalUnit, new HashSet<Unit>());
}
private Unit GetUnit(Unit organisationalUnit, HashSet<Unit> visited) {
if (visited.Contains(organisationalUnit)) {
throw new Exception("Cycle detected!"); // or just return null if you prefer
}
visited.Add(organisationalUnit);
if (organisationalUnit.IsMainUnit) {
return organisationalUnit;
}
if (organisationalUnit.Parent == null)
return null;
return GetUnit(organisationalUnit.Parent, visited);
}