4 Stimmen

Der rekursive Aufruf einer Func ist nicht immer möglich

Ich habe den folgenden Code, der etwas sehr Einfaches tut: besucht rekursiv einen Baum von Node-Objekten und berechnet die Summe einer Eigenschaft namens 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; }
    }    
}

Eine bessere Lösung wäre

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

Mein Problem und meine Frage ist: Warum kann ich die Funktion nicht innerhalb der Methode haben? Ich erhalte eine Fehlermeldung: Verwendung einer nicht zugewiesenen lokalen 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 : 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; }
    }    
}

10voto

Jon Skeet Punkte 1325502

Sie peut innerhalb der Methode haben, müssen Sie nur ein wenig tricksen, um die Tatsache zu umgehen, dass die rechte Seite Ihres Zuweisungsausdrucks die Verwendung einer lokalen Variablen beinhaltet, die nicht definitiv zugewiesen ist:

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

Damit wird das Problem der eindeutigen Zuordnung umgangen. Es ist gelegentlich etwas ärgerlich, und man kann sich vorstellen, dass es schön wäre, es zu beheben... aber es könnte einige interessante Situationen geben, in denen es wirklich ein Problem ist, aber relativ schwer in der Sprache zu beschreiben.

Um es anders auszudrücken: Ich vermute, dass die Festlegung der definitiven Zuweisungsregeln, die es erlauben, eine lokale Variable innerhalb eines Lambda-Ausdrucks nur dort zu lesen, wo es sicher ist (wo der Lambda-Ausdruck Teil der Zuweisung der Variablen ist), zu einer Änderung der Regeln führen würde. y der Delegat wird erst ausgeführt, nachdem die Zuweisung stattgefunden hat) würde mehr Komplexität hinzufügen als der relativ geringe Nutzen.

2voto

Amanda Mitchell Punkte 2627

Wie gesagt, können Sie fSum nicht verwenden, da es erst am Ende dieser Zeile vollständig zugewiesen wird. Wenn Sie es deklarieren, auf null setzen und dann auf diesen Wert setzen, wird es funktionieren.

2voto

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

0voto

Sean Punkte 58522

Schreiben Sie es als:

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X