递归调用函数并非总是可行的

4
我有以下代码,它执行非常简单的操作:递归访问Node对象树,并计算名为Info的属性的总和。
using System;

namespace ConsoleApplication11
{
    static class Program
    {
        static void Main(string[] args)
        {
            //tree of nodes
            var node = new Node {Info = 1, Left = new Node {Info = 1}};
            //print out sum
            Console.WriteLine(node.Sum());
            Console.ReadLine();
        }
        //find sum of Info of each node
        static int Sum(this Node node)
        {
            return node.Info + (node.Left == null ? 0 : Sum(node.Left)) + (node.Right == null ? 0 : Sum(node.Right));
        }
    }

    public class Node
    {
        public int Info { get; set; }
        public Node Left { get; set; }
        public Node Right { get; set; }
    }    
}

更好的解决方案是:
using System;
namespace ConsoleApplication11
{
    static class Program
    {
        static Func<Node, int> fSum = (node) => node.Info + (node.Left == null ? 0 : fSum(node.Left)) + (node.Right == null ? 0 : fSum(node.Right));

        static void Main(string[] args)
        {
            //tree of nodes
            var node = new Node {Info = 1, Left = new Node {Info = 1}};
            //print out sum
            Console.WriteLine(fSum(node));
            Console.ReadLine();
        }        
    }

    public class Node
    {
        public int Info { get; set; }
        public Node Left { get; set; }
        public Node Right { get; set; }
    }    
}

我的问题和疑问是:为什么我不能在方法内部使用函数?我得到了错误:使用未赋值的本地变量“fSum”。
using System;
namespace ConsoleApplication11
{
    static class Program
    {
        static void Main(string[] args)
        {
            //I am getting error: Use of unassigned local variable 'fSum'
            Func<Node, int> fSum = (node) => node.Info + (node.Left == null ? 0 : fSum(node.Left)) + (node.Right == null ? 0 : fSum(node.Right));

            //tree of nodes
            var n = new Node {Info = 1, Left = new Node {Info = 1}};
            //print out sum
            Console.WriteLine(fSum(n));
            Console.ReadLine();
        }        
    }

    public class Node
    {
        public int Info { get; set; }
        public Node Left { get; set; }
        public Node Right { get; set; }
    }    
}

这是 https://dev59.com/CXNA5IYBdhLWcg3wIqPr#1079609 的副本。 - Eric Lippert
对不起,这是重复的。抱歉,我没有意识到。 - user407665
4个回答

10

你可以在方法内部实现这个功能,但是需要稍微取巧一下,以解决赋值语句右侧包含未被定义的局部变量的问题:

Func<Node, int> fSum = null;
fSum = node => node.Info + (node.Left == null ? 0 : fSum(node.Left)) 
                         + (node.Right == null ? 0 : fSum(node.Right));

这种方法避免了明确赋值的问题。有时它会稍微有点烦人,你可以想象一下修复它会很好...但是可能存在一些真正的问题情况,但相对难以用语言描述。

换句话说:我怀疑修复明确赋值规则以允许在lambda表达式中仅在安全的情况下读取本地变量(即lambda表达式是分配变量的一部分,并且在分配完成后才执行委托)会增加更多复杂性,而收益相对较小。


2
......甚至需要更多的复杂性来实现相互递归,而空初始化解决方法在那里也适用。 - Ben Voigt

2
static void Main(string[] args) {

    //Declare the local variable first.
    Func<Node, int> fSum = null;

    //We are now able to reference the local variable from within the lambda.
    fSum = (node) =>
        node.Info + (node.Left == null ? 0 :
        fSum(node.Left)) + (node.Right == null ? 0 :
        fSum(node.Right));

    //tree of nodes
    var n = new Node {Info = 1, Left = new Node {Info = 1}};
    //print out sum
    Console.WriteLine(fSum(n));
    Console.ReadLine();
}

2

正如它所说,您不能使用fSum,因为它直到该行结束前才被完全分配。如果您声明它,将其设置为空,然后将其设置为该值,则可以运行。


0

请将其编写为:

Func<Node, int> fSum = null;
fSum= (node) => node.Info + (node.Left == null ? 0 : fSum(node.Left)) + (node.Right == null ? 0 : fSum(node.Right));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接