递归调用Func并不总是可行的

时间:2011-01-07 15:26:42

标签: c# .net lambda functional-programming

我有以下代码执行非常简单的操作:递归访问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; }
    }    
}

4 个答案:

答案 0 :(得分:10)

可以在方法中拥有它,你只需要稍微捏一下就可以解决你的赋值表达式的RHS包含使用局部变量的事实分配:

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表达式是赋值变量的一部分< em>和委托直到分配完成后才会执行)会增加比相对少量的利益更多的复杂性。

答案 1 :(得分:2)

正如它所说,你不能使用fSum,因为直到该行结束才完全分配。如果你声明它,将它设置为null,然后将其设置为该值,它将起作用。

答案 2 :(得分: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();
}

答案 3 :(得分:0)

将其写为:

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