开发者

Recursively calling a Func is not always possible

I have the following code that does something very simple: visits recursively a tree of Node objects and calculates the sum of a property named 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; }
    }    
}

A better solution would be

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; }
    }    
}

My problem and question is: why I can't have the function inside the method? I am getting error: Use of unassigned local variable '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 : fS开发者_StackOverflowum(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; }
    }    
}


You can have it within the method, you just need to fudge things a bit to get around the fact that the RHS of your assignment expression includes the use of a local variable which isn't definitely assigned:

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

That gets around the definite assignment issue. It's slightly annoying occasionally, and you can imagine that it would be nice to fix... but there could be some interesting situations where it's genuinely a problem, but relatively hard to describe in language terms.

To put it another way: I suspect that fixing the definite assignment rules to allow a local variable to be read within a lambda expression only where it would be safe to do so (where the lambda expression is part of assigning the variable and the delegate doesn't get executed until after the assignment has taken place) would add more complexity than the relatively small amount of benefit.


As it says, you can't use fSum because it isn't fully assigned until the end of that line. If you declare it, set it to null, and then set it to that value, it will work.


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();
}


Write it as:

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜