2015-06-02 7 views
7

Im folgenden Code versuche ich, Knoten in der Testmethode auf Null zu setzen. Wenn ich das tue, wird der Knoten Null nur innerhalb des Bereichs der Methode, aber "Eltern" wird nicht null. Mein Verständnis war, dass Objekte Methoden als Referenz übergeben werden und direkt in der Methode manipuliert werden können. Ich denke, dass etwas falsch in meinem konzeptionellen Verständnis ist. Können Sie erklären, warum das Zuordnen des Knotens zu null dem übergeordneten Element nicht den Wert null zuweist.Kann ein Objekt innerhalb einer Methode nicht auf Null setzen

class Program 
{ 
    static void Main(string[] args) 
    { 
     Node parent = new Node(); 
     parent.key = 50; 
     parent.left = new Node(); 
     Test.test(parent); 
    } 
} 

class Test 
{ 
    public static void test(Node node) 
    { 
     node.key = 1111; 
     node = null; 
    } 
} 

class Node 
    { 
     public object key { get; set; } 
     public Node left = null; 
     public Node right = null; 
    } 
+4

Sie übergeben * node * nach Wert (dh übergeben eine Kopie von es ist * handle *) und müssen es als Referenz übergeben (dh als das Original * handle *). Link: https://msdn.microsoft.com/en-us/library/8f1hz171.aspx und https://msdn.microsoft.com/en-us/library/14akc2c7.aspx –

+1

Vielen Dank für Ihre Antwort.Wie ändern sich die Feldwerte in diesem Fall? Beispiel: Wenn ich node.key = 1111 zuweise, ändert sich parent.key ebenfalls in 1111. – Karthikkumar

+1

Beachten Sie, dass das bevorzugte Mittel zum Zurückgeben von Werten aus einer Methode der Rückgabewert einer Funktion oder Eigenschaft ist, nicht als ref * oder * out *. Parameter wie Sie hier versuchen. Natürlich gibt es immer Ausnahmen. –

Antwort

3

Diese Da Parameter an Wert übergeben werden, wurde in Ihrer Testmethode eine Kopie der übergeordneten Variablen erstellt. Sie setzen die Kopie der Variablen einfach auf null. Sie können das Objekt dennoch bearbeiten, da die copy-Variable auf das Objekt im Heap verweist.

class Program 
{ 
    static void Main(string[] args) 
    { 
     Foo foo = new Foo(); 
     SetNull(foo); 

     Console.WriteLine(foo.ID);// print 2 
    } 

    private static void SetNull(Foo foo) 
    { 
     foo.ID = 2; 
     foo = null; 
    } 
} 


class Foo 
{ 
    public int ID { get; set; } 
} 
+0

Danke für die Erklärung! – Karthikkumar

1

Verwenden Sie das ref Stichwort:

public static void Test(ref Node node) { 
    node = null; 
} 

// Usage 

Node parent = ... 
Test(ref parent); 
Assert(parent == null); 
4

Sie sind nicht wirklich hier parent-node durch Verweis übergeben. Dies bedeutet, dass ein Wert von parent in node in der test Funktion kopiert wird. In diesem Fall zeigt dieser Wert einfach auf ein Objekt Node.

node.key = 1111 funktioniert wie erwartet, weil es diesen Wert verwendet, um auf dasselbe Objekt zuzugreifen, auf das auch parent verweist. d. h. sowohl node als auch parent enthalten Werte, die auf die gleichen Orte im Speicher zeigen. Als solche können beide die Modifikation beobachten. Wenn Sie also node = null sagen, weisen Sie der Variablen node innerhalb der test-Funktion einen neuen Wert zu. Das bedeutet, dass Sie den als Wert in dieser bestimmten Variablen gespeicherten Zeiger in null ändern, wodurch der Wert für parent - der immer noch auf das Objekt Node verweist - in keiner Weise geändert wird.

Geist meiner Amateur-ASCII-Art, aber ich denke, es ist wie diese Art von ist:

Test.test(parent);  

     <node object> 
     ^ ^
      .   . 
      .    . 
      .     . 
    +------.----+     . +-----------+ 
    |  . |      .   | 
    |  . | (-> copied to) | .  | 
    | parent |      | node | 
    +-----------+      +-----------+ 
    Program.Main scope     Test.test scope 


    node = null;  

     <node object> 
     ^
      . 
      . 
      . 
    +------.----+      +-----------+ 
    |  . |      |   | 
    |  . |      |   | 
    | parent |      | node=null | 
    +-----------+      +-----------+ 
    Program.Main scope     Test.test scope 

Während, wenn Sie public static void test(ref Node node) verwenden passieren Sie es wie folgt aus mehr denken können:

Test.test(parent);  

     <node object> 
     ^
      . 
      . 
      . 
    +------.----+      +-----------+ 
    | parent <============================ node | 
    |   |      |   | 
    |   |      |   | 
    +-----------+      +-----------+ 
    Program.Main scope     Test.test scope 


    node = null;  

     <node object> 
      Lonely 


    +-----------+      +-----------+ 
    | parent <============================ node | 
    |  =  |      |   | 
    | null |      |   | 
    +-----------+      +-----------+ 
    Program.Main scope     Test.test scope 
+0

Danke, jetzt verstehe ich! – Karthikkumar

+0

Streng genommen wird ein Verweis auf "Knoten" by-value übergeben (da "Klassen" -Instanzen Referenztypen sind), im Gegensatz zu "Knoten" selbst, der als Wert übergeben wird (falls dies der Fall wäre) eine 'Struktur'). – Dai

+0

tolle Ascii Darstellung Fähigkeiten! – fabriciorissetto

0

Rewrite diese Methode hier mit einem anderen Variablennamen für den Zweck Beispiel:

public static void test(Node PassedNode) 
    { 
     PassedNode.key = 1111; 
     PassedNode = null; 
    } 

PassedNode innerhalb der test Methode zeigt auf das Node parent = new Node(); Objekt, das zunächst in und so geführt wurde, wenn Sie das ändern Werte der Eigenschaften von PassedNode innerhalb der test-Methode, dann werden diese Änderungen das Objekt in der Main-Methode beeinflussen, weil es nur ein Objekt gibt. Wenn Sie PassedNode = null schreiben, dann zeigt PassedNode in der test Methode nicht mehr auf das ursprüngliche Objekt und das ist alles, was passiert: das Objekt selbst lebt noch weiter. Wenn Sie die ursprüngliche Referenz löschen möchten, müssen Sie dies in der aufrufenden Methode tun.

Verwandte Themen