Рекурсивный вызов Func не всегда возможен - PullRequest
4 голосов
/ 07 января 2011

У меня есть следующий код, который делает что-то очень простое: рекурсивно посещает дерево объектов 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 ]

10 голосов
/ 07 января 2011

Вы можете иметь это в методе, вам просто нужно немного выдумать, чтобы обойти тот факт, что RHS вашего выражения присваивания включает использование локальной переменной, которая точно не назначена:

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

Это решает проблему определенного назначения.Иногда это немного раздражает, и вы можете себе представить, что было бы неплохо исправить ... но могут быть некоторые интересные ситуации, когда это действительно проблема, но ее относительно сложно описать в языковых терминах.

Чтобы выразить этоДругой способ: я подозреваю, что исправление определенных правил присваивания, чтобы позволить локальной переменной быть прочитанной в лямбда-выражении только там, где это было бы безопасно (где лямбда-выражение является частью присвоения переменной и делегат не исполняется до тех пор, пока не будет выполнено назначение), что добавит больше сложности, чем сравнительно небольшое количество преимуществ.

2 голосов
/ 07 января 2011
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 голосов
/ 07 января 2011

Как говорится, вы не можете использовать fSum, потому что он не полностью назначен до конца этой строки.Если вы объявите это, установите для него значение null, а затем установите для этого значения, оно будет работать.

0 голосов
/ 07 января 2011

Напишите как:

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