【问题标题】:Recursion. Not all code paths return a value递归。并非所有代码路径都返回值
【发布时间】:2012-01-13 09:13:47
【问题描述】:

我确信我在这里犯了一个愚蠢的错误,但它打败了我。下面是一段代码:

void Main()
{
    //Key is a parent while the list contains its children
    Dictionary<string,List<string>> d = new Dictionary<string,List<string>>();
    d.Add("1",new List<string>(){"2","3"});//valid.should return false 
    d.Add("2",new List<string>(){"4"});//valid.should return false
    d.Add("3",new List<string>(){"5"});//valid.should return false
    d.Add("4",new List<string>(){"1"});//invalid.should return true 

   IsChildAlreadyAParent("4","2",d);
 }

private bool IsChildAlreadyAParent( string child, string parent, Dictionary<string, List<string>> d )
{           
    if( !d.ContainsKey( child ) || ( d.ContainsKey( child ) && d[child].Count == 0 ))
    {
        return false;
    }

    foreach( string childOfChild in d[child] )
     {
        if( childOfChild == parent )
            return true;

        if( IsChildAlreadyAParent( childOfChild, parent, d ) ) return true;
    }
}

编译它会给我这个错误:

IsChildAlreadyAParent(string, string, System.Collections.Generic.Dictionary&lt;string,System.Collections.Generic.List&lt;string&gt;&gt;)': 并非所有代码路径都返回值

我已经阅读了几次代码,但我看不出如何会错过返回条件。我知道我可以通过在方法结束之前添加方法返回语句来纠正它,但这并不能帮助我理解手头的问题。差距在哪里??

【问题讨论】:

    标签: c# recursion


    【解决方案1】:

    你可能认为这只会执行一次循环体,总是从函数返回:

    foreach( string childOfChild in d[child] )
    {
        if( childOfChild == parent )
            return true;
    
        return IsChildAlreadyAParent( childOfChild, parent, d );
    }
    

    但是如果d[child] 根本没有元素呢?

    另外,只测试第一个孩子也可能不是正确的解决方案。

    更好:

    foreach( string childOfChild in d[child] )
    {
        if( childOfChild == parent ) return true;
        if (IsChildAlreadyAParent( childOfChild, parent, d )) return true;
    }
    return false;
    

    【讨论】:

    • 修改了代码来处理这个问题......仍然是同样的问题,我不想像你在这里所做的那样在最后使用方法返回......
    • 但提出的观点,“只测试第一个孩子可能也不是正确的解决方案”,很有帮助
    • @wanderer:抱歉,编译器不够聪明,无法注意到您已经测试了一个空列表。所以它仍然关心循环下面发生的事情。
    【解决方案2】:

    编译器抱怨是因为在d[child] 集合为空的情况下,循环体将永远不会运行。该特定代码路径上没有return,因此您会收到错误消息。

    此外,如果成功执行,您的代码版本将在字典中查找 child 3 次。您可以对此进行优化,使其仅使用 TryGetValue 进行一次查找。

    这是带有几个修复的代码

    private bool IsChildAlreadyAParent(
      string child, 
      string parent, 
      Dictionary<string, List<string>> d )
    {           
        List<string> list;
        if (!d.TryGetValue(child, out list) || list.Count == 0)
        {
            return false;
        }
    
        if (list[0] == parent)
        {
          return true;
        }
    
        return IsChildAlreadyAParent(list[0], parent, d );
    }
    

    【讨论】:

    • @wanderer 我的错,修正了错字。现在应该编译
    • @wanderer 是的,但这就是您的原始样本的功能。该循环只进行了一次迭代。它要么匹配parent,要么立即调用IsChildAlreadyAParent,有效地使用list[0]。
    • @jaredpar....我的错..对不起。是个错误...我想迭代检查条件的完整列表。
    【解决方案3】:

    如果d[child] 的长度为 0 会怎样?所以你的for循环不会运行->没有返回值

    【讨论】:

      【解决方案4】:

      您的代码可能永远不会进入“foreach”...您应该在最后返回...如果 d[child] 根本没有元素...

      【讨论】:

        【解决方案5】:

        如果你的列表是空的怎么办?

        更不用说 foreach 循环毫无意义。它总是在第一次迭代时终止。

        【讨论】:

          猜你喜欢
          • 2011-12-17
          • 1970-01-01
          • 2012-12-03
          • 1970-01-01
          • 2021-11-08
          • 2013-10-06
          • 2016-02-14
          相关资源
          最近更新 更多