2016-08-10 1 views
-2

So lief ich in diesen Fehler, wo C# verhält wie ich in einer Liste durch Verweis und nicht nach Wert, wie es normalerweise passiert. Lassen Sie mich ein Beispiel zeigen:Wierd Weg C# übergibt in Listen als Argumente

using System; 
using System.Collections.Generic; 

namespace testprogram 
{ 
    class Program 
    { 
     static int x; 
     static List<Coordinate> coordinates; 

     static void Main(string[] args) 
     { 
      x = 10; 
      coordinates = new List<Coordinate>(); 
      coordinates.Add(new Coordinate(0, 0)); 
      coordinates.Add(new Coordinate(1, 1)); 

      testfunction(x, coordinates); 
      Console.WriteLine(x); 
      foreach (var objekt in coordinates) 
      { 
       Console.WriteLine(objekt.xpos); 
       Console.WriteLine(objekt.ypos); 
      } 
      Console.Read(); 
     } 

     static void testfunction(int test, List<Coordinate> objects) 
     { 
      test = 4; 

      foreach (Coordinate obj in objects) 
      { 
       obj.xpos = 4; 
       obj.ypos = 4; 
      } 
     } 


    } 

    class Coordinate 
    { 
     public int xpos; 
     public int ypos; 

     public Coordinate(int new_x, int new_y) 
     { 
      xpos = new_x; 
      ypos = new_y; 
     } 
    } 
} 

Dieser Code gibt:

10 
4 
4 
4 
4 

Aber warum? Ich erwartete, es zu sein:

10 
0 
0 
1 
1 

Ich habe versucht, eine zusätzliche Liste in der Funktion zu machen und den Wert des Parameters zuweisen, aber auch, dass nicht funktioniert. Gibt es eine Umgehungsmöglichkeit dafür?

+1

Primitive Typen (int) werden nach Wert übergeben. Objekte (z. B. Liste ) wird durch Verweis übergeben ... Siehe C# 101 Vorwort ... – Roland

+0

Liste ist inhärent ein Referenztyp, während Ihr Int nicht ist. Beide werden nach Wert übergeben, aber für eine Liste, deren Wert kopiert wurde, handelt es sich um einen (neuen) Zeiger, der auf die zugrunde liegende Liste SAME verweist. Also werden die List-Werte wirklich aktualisiert, während das Int nicht ist. – SlimsGhost

+0

Ich denke, das ist eine gute Anfängerfrage. Ich glaube nicht, dass hier Minusabstimmungen angebracht sind. Ich stimme die Frage +1. –

Antwort

0

Ihre Erwartungen sind falsch. Die Liste wird als Wert übergeben. Dies bedeutet, dass die Variable objects eine Wertkopie der ursprünglichen Listenvariablen ist. Aber die Liste enthält Referenzen, ich meine, der Inhalt der Liste sind Verweise auf Coordinate Objekte. Wenn Sie also versuchen würden, die Listenvariable wie objects = new List<>() zu ändern, würde dies Ihre ursprüngliche Liste nicht ändern. Wenn Sie jedoch die Objekte in der Liste ändern, werden die Änderungen tatsächlich auf die ursprüngliche Liste angewendet.

objects[0] = new Coordinate(5, 5); 
objects[0].xpos = 6; 

Diese beiden Beispiele ändern die ursprüngliche Liste.

Wenn Sie die Möglichkeit haben möchten, etwas in der Liste sicher zu ändern, müssen Sie einen tiefen Klon davon erstellen. Sie können die Clone() -Methode verwenden, aber es kann schwierig sein, da Sie jedes Objekt in der Liste manuell klonen müssen. Dies wurde bereits hier beantwortet: How create a new deep copy (clone) of a List<T>?

+0

Ok, das macht Sinn. Aber wie kann ich das umgehen? Vielleicht eine Möglichkeit, eine Liste und ihre Objekte oder etwas zu duplizieren? – HarryGoatleaf

+0

Wenn Sie die Möglichkeit haben möchten, etwas in der Liste sicher zu ändern, müssen Sie einen tiefen Klon davon erstellen. Sie können die Clone() -Methode verwenden, aber es kann schwierig sein, da Sie jedes Objekt in der Liste manuell klonen müssen. –

+0

@AlKepp - in diesem speziellen Fall sollte es in Ordnung sein, da 'Coordinate' nur Werttypen enthält, so dass ein oberflächlicher Klon ausreicht. – LeopardSkinPillBoxHat

0

Sie haben einen Verweis auf die Liste "nach Wert" übergeben. Wenn Sie also in "testfunction" die Referenz "object" ändern, werden "coordinates" nicht geändert (als Zeiger). Aber das Ändern der Elemente von "Objekt" wirkt sich auf die Elemente von "Koordinaten" aus.

1

Das Argument List<T> ist ein Referenztyp, der als Wert übergeben wird.

Wenn Sie Elemente in der Liste in der Methode ändern, bleiben diese beim Verlassen der Methode erhalten.

Wenn Sie jedoch die Referenz innerhalb der Methode zuweisen, werden diese Änderungen außerhalb der Methode verloren. Wenn Sie einen Parameter als Verweis übergeben möchten, verwenden Sie das ref Stichwort:

static void testfunction(int test, ref List<Coordinate> objects) 
{ 
    // This will update objects outside the testfunction method 
    objects = new List<Coordinate>(); 
} 

können Sie auch die out Schlüsselwort verwenden, die dem ref Schlüsselwort ähnlich funktioniert. Der einzige Unterschied besteht darin, dass Sie keine Werte initialisieren müssen, die als out Parameter übergeben werden, bevor Sie die Methode aufrufen, und sie müssen initialisiert werden, bevor Sie die Methode verlassen.

static void Main(string[] args) 
{ 
    // No need to initialise variable passed as "out" parameter 
    List<Coordinate> objects; 
    testfunction(test, out objects); 
} 

static void testfunction(int test, out List<Coordinate> objects) 
{ 
    // Removing this line would result in a compilation error 
    objects = new List<Coordinate>(); 
} 
+0

@Dispersia - Sie können den Unterschied zwischen Referenz- und Werttypen [hier] lesen (http://stackoverflow.com/questions/5057267/what-is-the-difference-between-a-reference-type-and-value- Typ-in-c). Stellen Sie sich eine Referenz wie einen Zeiger auf einen anderen Wert vor. Wenn ich sage, dass ein Verweis tpye nach Wert übergeben wird, bedeutet dies, dass der "Zeiger" -Wert übergeben wird und wenn dieser "Zeiger" -Wert innerhalb der Methode aktualisiert wird (z. B. ein neues Objekt erstellt wird oder auf ein anderes Objekt gezeigt wird) Diese Änderung wird nicht außerhalb der Methode gesehen. – LeopardSkinPillBoxHat