Feld mit List (of String) kopieren

  • VB.NET

Es gibt 8 Antworten in diesem Thema. Der letzte Beitrag () ist von Christoph1972.

    Feld mit List (of String) kopieren

    Hallo zusammen,

    ich habe eine Frage: Wie kann man ein Feld kopieren, das List (of String) enthält? Ich kann zwar eine Kopie erstellen, aber in der Kopie ändern sich die Werte der Liste, wenn das Originalfeld geändert wird.

    Hier mein Code:

    Public Class Eigenschaften 'Klasse Eigenschaften definieren
    Public i,j As Integer
    Public FW As List(Of String)
    Public Status As String
    End Class


    Class Form1
    Dim Feld(), Kopie_von_Feld() as Eigenschaften
    :
    :
    :
    Sub rechne
    :
    :
    : [Werte in Feld schreiben]
    : array.copy(Feld, Kopie_von_Feld, Feld.length) 'Kopie_von_Feld erstellen
    :
    :
    ; [Werte in Feld ändern]
    :
    :
    : [Kopie_von_Feld untersuchen]
    :
    :
    : End Sub

    An der Stelle "Kopie_von_Feld untersuchen stelle ich fest, dass in i, j und Status wie erwartet die Werte zum Zeitpunkt des Kopierens stehen, aber in FW werden in der Kopie die Werte geändert, wenn sie im Orignal Feld geändert werden. Ich suche nun eine Möglichkeit, eine Kopie von Feld zu erstellen, in der alle Werte erhalten bleiben, wenn sich die Werte in Feld ändern. Ich habe auch mal prbiert, anstatt einer Class Eigenschaften eine Structure Eigenschaften zu definieren, aber damit hat es auch nicht funktioniert. Wenn jemand einen Tip dazu hat, wäre das absolut genial.

    Vielen Dank und Gruß
    Weber
    Okay, ich versuche mich mal an einer Erklärung:

    Egal ob du eine Struct oder Class hast, die Property FW von Eigenschaften ist vom Typ List(Of string). List ist ein Referenztyp, demnach hast du in FW eine Referenz auf eine Liste. Wenn man nun ein Class-Objekt "kopiert" so wird die Referenz auf eben dieses Objekt in das neue Array kopiert. Wenn man eine Struct kopiert, so werden alle Properties des Struct-Objektes kopiert, einschließlich der Referenz auf die List(Of String). Daher hast du in jedem Fall in beiden Arrays Referenzen auf dieselbe Liste.

    Andere Frage, warum musst du kopieren? kannst du nicht das Array Feld weiterbenutzen?
    Danke für die Antwort.

    Ich brauche deshalb eine Kopie von Feld, weil ich für spätere Berechnungen die Orignalwerte wieder benötige. Ich suche deshalb eine Möglichkeit, den kompletten Inhalt von Feld zu speichern, um ihn für spätere Berechnungen wieder zur Verfügung zu haben.

    Gruß
    Weber
    Das läuft z.B. über SecondList.AddRange(FirstList.ToArray):

    VB.NET-Quellcode

    1. Dim FirstList As New List(Of String)
    2. FirstList.Add("abc")
    3. Dim SecondList As New List(Of String)
    4. SecondList.AddRange(FirstList.ToArray)
    5. SecondList(0) = "def"
    6. If FirstList(0) = SecondList(0) Then
    7. MessageBox.Show("Oh no!")
    8. Else
    9. MessageBox.Show("Das Kopieren der Liste war erfolgreich.")
    10. End If

    Und auch die SecondList kann man dann über .ToArray in ein Feld verwandeln.
    Aber hier gilt das, was Dir als Tip gegeben wurde: Das klappt nur bei Wertetypen! Hat man eine List(Of IrgendEineKlasse), ist aus die Maus, da da wieder nur mit Referenzen gearbeitet wird.
    Aber wozu Felder benutzen? Sind die wirklich notwendig? Eine List ist um einiges flexibler und weniger störanfällig. Falls man wirklich (z.B. für einen Aufruf einer externen Funktion) ein Array braucht, kann man die immer noch wie genannt in ein Array umwandeln.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „VaporiZed“ ()

    Hallo zusammen,

    inzwischen habe ich mit Eurer Hilfe das Problem gelöst. Ich habe in meine Klasse ein Feld FW_Sicherung eingebaut sowie ein Sichern- und Restore-Programm

    Public Class Eigenschaften 'Klasse Eigenschaften definieren
    Public i,j As Integer
    Public FW As List(Of String)
    Public Status As String
    Dim FW_Sicherung() As String

    Public Sub Sichern() 'Sichern von FW
    FW_Sicherung = FW.ToArray
    End Sub
    Public Sub Restore() 'Wiederherstellen von FW
    FW = FW_Sicherung.ToList
    End Sub
    End Class


    Nochmal Danke für den Tip!

    Gruß Weber
    Für sowas sind Extension Methods eine feine Sache:

    Extension

    VB.NET-Quellcode

    1. Public static Class ListStringExtension
    2. Public Shared Function Clone(ByVal List<string> As Me, ByVal listToClone As List<string>) As List<string>
    3. Dim newList As List<string> = New List<string>()
    4. list.ForEach(x => newList.Add(x))
    5. Return newList
    6. End Function
    7. End Class


    Verwendung

    VB.NET-Quellcode

    1. Dim list As List<string> = New List<string>()
    2. list.Add("Hans")
    3. list.Add("Wurst")
    4. Dim cloneList As List<string> = list.Clone(list)
    Gruß
    Christoph
    @Christoph1972 das was deine Extension macht, erreichst du auch ganz einfach über ein DeineList.ToList():

    Auszug aus der ReferenceSource

    C#-Quellcode: System.Linq.Enumerable

    1. public static List<TSource> ToList<TSource>(this IEnumerable<TSource> source) {
    2. if (source == null) throw Error.ArgumentNull("source");
    3. return new List<TSource>(source);
    4. }

    Der Konstruktor von List<TSource> hat nun 2 Vorgehensweisen. Sollte es sich um eine ICollection handeln, so wird ein CopyTo ausgeführt, was letztenendes auf ein Array.Copy hinausläuft, wenn nicht, läuft er den Enumerator des IEnumerables durch, was einem ForEach entsprechen würde.

    Hier der genaue Quellcode des Konstruktors und der CopyTo methode.
    "Kompliziert"

    C#-Quellcode: System.Collections.Generc.List<T>.ctor

    1. public List(IEnumerable<T> collection) {
    2. if (collection==null)
    3. ThrowHelper.ThrowArgumentNullException(ExceptionArgument.collection);
    4. Contract.EndContractBlock();
    5. ICollection<T> c = collection as ICollection<T>;
    6. if( c != null) {
    7. int count = c.Count;
    8. if (count == 0)
    9. {
    10. _items = _emptyArray;
    11. }
    12. else {
    13. _items = new T[count];
    14. c.CopyTo(_items, 0);
    15. _size = count;
    16. }
    17. }
    18. else {
    19. _size = 0;
    20. _items = _emptyArray;
    21. // This enumerable could be empty. Let Add allocate a new array, if needed.
    22. // Note it will also go to _defaultCapacity first, not 1, then 2, etc.
    23. using(IEnumerator<T> en = collection.GetEnumerator()) {
    24. while(en.MoveNext()) {
    25. Add(en.Current);
    26. }
    27. }
    28. }
    29. }

    C#-Quellcode: System.Collections.Generc.List<T>.CopyTo

    1. public void CopyTo(T[] array, int arrayIndex) {
    2. // Delegate rest of error checking to Array.Copy.
    3. Array.Copy(_items, 0, array, arrayIndex, _size);
    4. }