Wie kopiere ich eine List<T> bei Value und nicht bei Reference in C# (wie lege ich eine unabhängige Kopie der Liste an)?

  • C#
  • .NET (FX) 4.5–4.8

Es gibt 25 Antworten in diesem Thema. Der letzte Beitrag () ist von RodFromGermany.

    C#-Quellcode

    1. ​class Test
    2. {
    3. public int i;
    4. public string s;
    5. public void Start()
    6. {
    7. List<Test> Original = new List<Test>()
    8. {
    9. new Test() { i = 1, s = "Huhu"},
    10. new Test() { i = 1, s = "Hallo"},
    11. new Test() { i = 1, s = "Servus"}
    12. };
    13. List<Test> Backup;
    14. foreach (var item in Original)
    15. {
    16. Console.WriteLine($"{item.i} {item.s}");
    17. }
    18. Backup = new List<Test>(Original);
    19. Original.Clear();
    20. foreach (var item in Original)
    21. {
    22. Console.WriteLine($"{item.i} {item.s}");
    23. }
    24. Original = Backup;
    25. foreach (var item in Original)
    26. {
    27. Console.WriteLine($"{item.i} {item.s}");
    28. }
    29. Console.ReadKey();
    30. }
    31. }


    Ich weiss nicht ob es das ist was du meinst. Wenn nicht einfach ignorieren.^^
    @Maffi Ich hab das so in meinem Beispiel nicht reproduzieren können. Schon seltsam. Dein Code macht was ich eigentlich machen möchte, ABER wenn ich ein neues Item hinzufüge, dann doch nicht mehr Hast Du keinen Code laufen lassen? Falls ja könntest Du mal in Zeile 23. Original.Add(4,"Moin"); einfügen (also nach dem Backup). Dann taucht dieser Eintrag später beim Abruf des Backups wieder auf. Das ist nicht gewollt. Also keine unabhängige Kopie. Leider.

    Eben beim Schreiben ist mir der Gedanke gekommen, dass das wahrscheinlich so ist:

    Original zeigt auf die AnfangsSpeicherAdresse der Liste!
    Backup zeigt nach dem Kopieren auf dieselbe SpeicherAdresse!
    Nach dem Löschen von Original wird aber nur der "Zeiger" (mit dem Namen Orginal) der auf den Speicher zeigt als "leer" zurückgegeben. Wobei der Zeiger Backup immer noch den selben Speicherbereich anzeigt wir Original (daher auch immer noch mit der Änderung die nicht da sein soll). Es gibt wohl keinen trivialen weg in C# den Speicherinhalt physikalisch zu kopieren und mit einem Zeiger "Backup" zu verknüpfen. Daher dann wohl auch die LSG von den Profis das Binär in den Speicher zu schreiben. Bitte verzeiht mir, falls ich das nicht korrekt wieder gegeben habe. Ich hoffe das es klar ist was ich sagen will, auch wenn das im Detail sicher anders beschreiben werden müsste.
    codewars.com Rank: 4 kyu

    C#-Quellcode

    1. ​class Test
    2. {
    3. public int i;
    4. public string s;
    5. public void Start()
    6. {
    7. List<Test> Original = new List<Test>()
    8. {
    9. new Test() { i = 1, s = "Huhu"},
    10. new Test() { i = 2, s = "Hallo"},
    11. new Test() { i = 3, s = "Servus"}
    12. };
    13. List<Test> Backup;
    14. foreach (var item in Original)
    15. {
    16. Console.WriteLine($"{item.i} {item.s}");
    17. }
    18. Backup = new List<Test>(Original);
    19. Original.Clear();
    20. Original.Add(new Test() { i = 3, s = "Servus" });
    21. Original.Add(new Test() { i = 2, s = "Hallo" });
    22. Original.Add(new Test() { i = 1, s = "Huhu" });
    23. foreach (var item in Original)
    24. {
    25. Console.WriteLine($"{item.i} {item.s}");
    26. }
    27. Original = new List<Test>(Backup);
    28. foreach (var item in Original)
    29. {
    30. Console.WriteLine($"{item.i} {item.s}");
    31. }
    32. foreach (var item in Backup)
    33. {
    34. Console.WriteLine($"{item.i} {item.s}");
    35. }
    36. Console.ReadKey();
    37. }
    38. }
    @Maffi Ja und:

    C#-Quellcode

    1. // ...
    2. Original = new List<Test>(Backup);
    3. Original[1].i = 42; // kleine Ergänzung
    4. foreach (var item in Original)
    5. {
    6. Console.WriteLine($"{item.i} {item.s}");
    7. }
    8. foreach (var item in Backup)
    9. {
    10. Console.WriteLine($"{item.i} {item.s}");
    11. }
    12. //Console.ReadKey();

    Geht iwie am Ziel vorbei, oder?
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Ja da hast du recht @RodFromGermany, da die Referenzen und nicht die Objekte (Elemente) kopiert werden.

    Dann würde ich es so machen.

    Spoiler anzeigen

    C#-Quellcode

    1. ​class Test
    2. {
    3. private int I;
    4. private string S;
    5. public Test(int i, string s)
    6. {
    7. I = i;
    8. S = s;
    9. }
    10. public void Start()
    11. {
    12. List<Test> ListOne = new List<Test>();
    13. List<Test> ListTwo = new List<Test>();
    14. List<Test> ListThree = new List<Test>();
    15. BackUpLaden(ListOne);
    16. ElementeKopieren(ListOne, ListTwo, ListThree);
    17. ListenAusgabe(ListOne, ListTwo, ListThree);
    18. // ändern eines Elementes und löschen des letzten Elementes in ListTwo - keine Auswirkung auf die beiden anderen Listen
    19. ListTwo[1].I = 9;
    20. ListTwo[1].S = "X";
    21. ListTwo.RemoveAt(2);
    22. ListenAusgabe(ListOne, ListTwo, ListThree);
    23. // ändern eines Elementes und hinzufügen eines neuen Elementes in ListThree - keine Auswirkung auf die beiden anderen Listen
    24. ListThree[2].I = 8;
    25. ListThree[2].S = "Y";
    26. ListThree.Insert(3, new Test(I = 9, S = "X"));
    27. ListenAusgabe(ListOne, ListTwo, ListThree);
    28. ListTwo.Clear();
    29. ListThree.Clear();
    30. ElementeKopieren(ListOne, ListTwo, ListThree);
    31. ListenAusgabe(ListOne, ListTwo, ListThree);
    32. // ändern aller Elemente und hinzufügen neuer Elemente in ListOne - keine Auswirkung auf die beiden anderen Listen
    33. ListOne[0].I = 9;
    34. ListOne[0].S = "CC";
    35. ListOne[1].I = 8;
    36. ListOne[1].S = "BB";
    37. ListOne[2].I = 7;
    38. ListOne[2].S = "AA";
    39. ListOne.Insert(3, new Test(I = 9, S = "X"));
    40. ListOne.Insert(4, new Test(I = 99, S = "XX"));
    41. ListOne.Insert(5, new Test(I = 999, S = "XXX"));
    42. ListenAusgabe(ListOne, ListTwo, ListThree);
    43. ListOne.Clear();
    44. BackUpLaden(ListOne);
    45. ListenAusgabe(ListOne, ListTwo, ListThree);
    46. }
    47. private void BackUpLaden(List<Test> lst)
    48. {
    49. lst.Add(new Test(I = 1, S = "A"));
    50. lst.Add(new Test(I = 2, S = "B"));
    51. lst.Add(new Test(I = 3, S = "C"));
    52. }
    53. private void ElementeKopieren(List<Test> lst1, List<Test> lst2, List<Test> lst3)
    54. {
    55. foreach (var item in lst1)
    56. {
    57. lst2.Add(new Test(item.I, item.S));
    58. lst3.Add(new Test(item.I, item.S));
    59. }
    60. }
    61. private void ListenAusgabe(List<Test> lst1, List<Test> lst2, List<Test> lst3)
    62. {
    63. foreach (var item in lst1)
    64. {
    65. Console.Write($"{item.I}{item.S,-4}");
    66. }
    67. Console.WriteLine();
    68. foreach (var item in lst2)
    69. {
    70. Console.Write($"{item.I}{item.S,-4}");
    71. }
    72. Console.WriteLine();
    73. foreach (var item in lst3)
    74. {
    75. Console.Write($"{item.I}{item.S,-4}");
    76. }
    77. Console.WriteLine("\n-------------");
    78. }
    79. }

    Maffi schrieb:

    Dann würde ich es so machen.
    Hast Du Dir mal Post #2 angesehen?
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!