2015-06-02 15 views
7

Nel codice seguente sto tentando di impostare il nodo su null nel metodo di prova. Quando lo faccio, il nodo diventa Nullo solo nell'ambito del metodo, ma "genitore" non diventa nullo. La mia comprensione è che gli oggetti sono passati ai metodi come riferimento e possono essere manipolati direttamente all'interno del metodo. Penso che ci sia qualcosa di sbagliato nella mia comprensione concettuale. Puoi spiegare perché l'assegnazione del nodo a null non assegna il padre a null.Impossibile impostare un oggetto su null all'interno di un metodo

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

Si sta passando * nodo * in base al valore (ovvero passando una copia del suo * handle *), e occorre passarlo per riferimento (cioè come originale * handle *). Link: https://msdn.microsoft.com/en-us/library/8f1hz171.aspx e https://msdn.microsoft.com/en-us/library/14akc2c7.aspx –

+1

Grazie per la risposta.In tal caso, come cambiano i valori dei campi? Esempio quando assegno node.key = 1111, parent.key cambia anche in 1111. – Karthikkumar

+1

Nota che il metodo preferito per restituire valori da un metodo è come valore di ritorno di una funzione o di una proprietà, non come un riferimento * o * un * parametro come si sta tentando qui. Certo, ci sono sempre delle eccezioni. –

risposta

3

Questo è perché i parametri vengono passati per valore, quindi nel metodo di test è stata creata una copia della variabile padre, si sta semplicemente impostando la copia della variabile su null. Sebbene sia ancora possibile manipolare l'oggetto perché la variabile di copia punta all'oggetto nell'heap.

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

Grazie per la spiegazione! – Karthikkumar

1

Utilizzare la parola chiave ref:

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

// Usage 

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

Non sta effettivamente passando parent-node per riferimento qui. Ciò significa che un valore di parent viene copiato su node nella funzione test. In questo caso, quel valore punta semplicemente a un oggetto Node.

node.key = 1111 funziona come previsto poiché utilizza tale valore per accedere allo stesso oggetto a cui punta anche parent. Ad esempio, entrambi node e parent contengono valori che puntano alle stesse posizioni nella memoria. In quanto tale, entrambi possono osservare la modifica.

Tuttavia quando si dice node = null, si assegna un nuovo valore alla variabile node all'interno della funzione test. Ciò significa che stai cambiando il puntatore memorizzato come valore in quella particolare variabile su null, che non modifica in alcun modo il valore per parent - che sta ancora puntando all'oggetto Node.

Mente mia arte ASCII dilettante, ma penso che sia un po 'come questo:

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 

Mentre se ti è capitato di utilizzare public static void test(ref Node node) si potrebbe pensare di più come questo:

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

Grazie, ora capisco! – Karthikkumar

+0

In senso stretto, un reference-to-'node' viene passato per -valore (dato che le istanze' class' sono Reference-types), invece che 'node' stesso viene passato per valore (se lo sarebbe se fosse una 'struct'). – Dai

+0

ottime capacità di rappresentazione ascii! – fabriciorissetto

0

Rewrite questo metodo qui con un nome di variabile diverso allo scopo di esempio:

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

PassedNode all'interno del metodo test punti all'oggetto Node parent = new Node(); che è stato inizialmente superati e quindi quando si modifica il i valori delle proprietà di PassedNode all'interno del metodo test, quindi queste modifiche influiranno sull'oggetto nel metodo Main perché esiste un solo oggetto. Quando si scrive PassedNode = null quindi PassedNode nel metodo test non indica più l'oggetto originale e questo è tutto ciò che accade: l'oggetto stesso continua a vivere. Se si desidera cancellare il riferimento originale, è necessario farlo nel metodo di chiamata.

Problemi correlati