2013-05-24 8 views
5

Ok das ist ein bisschen schwer zu fragen, aber ich werde es versuchen. Ich habe eine Liste mit Objekten (Lots), die wieder eine Liste mit Objekten (Wafers) enthält. Wenn ich einen Wert innerhalb eines Wafers ändere, wird er in beiden Listen geändert! Das ist, was ich will. Aber wenn ich einen Wafer aus der kopierten Liste entfernen möchte, sollte es nicht aus der ursprünglichen Liste entfernt werden. Ich möchte also eine neue Liste von Wafern in jeder Charge haben, aber die Referenzen zu den Wafern sollten die gleichen wie in der ursprünglichen Charge sein, da ich die Werte auf den Wafern ändern möchte und die Werte im Originalwafer und im kopierten Wafer ändern sollte . Ist es möglich ohne tiefere Kopie?Ist es möglich, Elemente in einer Liste einer Liste zu entfernen, ohne die ursprüngliche Referenz zu verlieren?

Ich habe den folgenden Code, es besser zu erklären:

public class Lot 
    { 
     public string LotName { get; set; } 

     public List<Wafer> Wafers { get; set; } 
    } 

    public class Wafer 
    { 
     public string WaferName { get; set; } 

    } 
    [Test] 
    public void ListInListTest() 
    { 
        //Some Testdata 

     List<Lot> lotList = new List<Lot>(); 
     Lot lot = new Lot(); 
     lot.LotName = "Lot1"; 
     lot.Wafers = new List<Wafer>(); 
     Wafer wafer = new Wafer(); 
     wafer.WaferName = "Wafer1"; 
     lot.Wafers.Add(wafer); 
     wafer = new Wafer(); 
     wafer.WaferName = "Wafer2"; 
     lot.Wafers.Add(wafer); 
     wafer = new Wafer(); 
     wafer.WaferName = "Wafer3"; 
     lot.Wafers.Add(wafer); 
     wafer = new Wafer(); 
     wafer.WaferName = "Wafer4"; 
     lot.Wafers.Add(wafer); 
     lotList.Add(lot); 

     lot = new Lot(); 
     lot.LotName = "Lot1"; 
     lot.Wafers = new List<Wafer>(); 
     wafer = new Wafer(); 
     wafer.WaferName = "Wafer1"; 
     lot.Wafers.Add(wafer); 
     wafer = new Wafer(); 
     wafer.WaferName = "Wafer2"; 
     lot.Wafers.Add(wafer); 
     wafer = new Wafer(); 
     wafer.WaferName = "Wafer3"; 
     lot.Wafers.Add(wafer); 
     wafer = new Wafer(); 
     wafer.WaferName = "Wafer4"; 
     lot.Wafers.Add(wafer); 
     lotList.Add(lot); 

     //Copy the List 
     List<Lot> copyList = CopyList(lotList); 

     //That works. It removes the lot just in the copyList but not in 
     //the original one 
     copyList.RemoveAt(1); 

     //This works not like i want. It removes the wafers from the copied list 
     //and the original list. I just want, that the list will be changed 
     //in the copied list 
     copyList[0].Wafers.RemoveAt(0); 


    } 

    private List<Lot> CopyList(List<Lot> lotList) 
    { 
     List<Lot> result = new List<Lot>(lotList); 

     foreach (Lot lot in result) 
     { 
      lot.Wafers = new List<Wafer>(lot.Wafers); 
     } 

     return result; 
    } 

Ich hoffe, es ist nicht so verwirrend ist? Und ich hoffe meine Frage ist gut genug erklärt.

+0

Sie können dies ausprobieren http://stackoverflow.com/questions/1582285/how-to-remove-elements-from-a-generic-list-while-iterating-over-it –

+0

Sie können versuchen, zu serialisieren und Dann deserialize ohne eine tiefe Kopie – Saravanan

+1

Sind Sie sicher, dass es nicht funktioniert? Es scheint, dass Sie es richtig machen: Erstellen Sie eine neue Liste von Wafern (das ist wichtig), die von vorhandenen Referenzen ausgefüllt wird. Sollte arbeiten. – JeffRSon

Antwort

2

Soweit ich sehen kann, gibt es keine Out-of-the-Box-Möglichkeit für Sie zu tun, was Sie wollen. Hier eine kurze Beschreibung warum:

Die List<Lot> (ganz links) enthält einen Verweis auf das Objekt Lot, das wiederum Verweise auf seine beiden Elementvariablen enthält.

enter image description here

Wenn Sie Änderungen wollen die LotName und Bestandteile der Wafers Liste propagiert werden, wie Sie beschreiben, ist die einfachste Lösung, einen Verweis auf das Lot Objekt zwischen den Listen zu teilen:

enter image description here

Jetzt können Sie sehen, warum es unmöglich ist, die Elemente in der Liste Wafers unabhängig mit dieser Lösung zu ändern - Sie können nicht davon wegkommen, dass Sie ein Verwenden Sie den gleichen Objektreferenz!

Durch das Teilen einer Referenz verliert man die Möglichkeit, die Unterschiede im Verhalten zu steuern. Um zu erreichen, was Sie wollen, denke ich, müssen Sie eine tiefe Kopie der Lot Instanzen machen, und Sie könnten dann die Verbreitung von Änderungen durch eine Art von Observer Muster verwalten.

+0

Wow, danke. Das macht die Dinge für mich klarer! Wenn ich also "neue Liste ()" anrufe, wird nur eine neue Liste für dieselbe Chargenreferenz erstellt. OK .. als ich tiefe Kopie machen muss. :/ –

0

Das Problem ist, dass Sie die Klonliste erstellen, indem Sie eine Referenz mit der Hauptliste pflegen. Sie sollten etwas wie verwenden:

private List<Lot> CopyList(List<Lot> list) 
{ 
    List<Lot> clone = new List<Lot>(); 

    foreach(Lot l in list) 
    { 
     List<Wafer> wafers = new List<Wafer>(); 
     foreach(Wafer w in l.Wafers) 
     wafers.Add(w); 

     clone.Add(new Lot(){ LotName = l.LotName, Wafers = wafers }); 
    } 

    return clone; 
} 
+0

Kein neuer Wafer soll erstellt werden, scheint es. Nur die Referenzen müssen beibehalten werden. – JeffRSon

+0

Nein, er benötigt den Verweis auf _Wafer_ nicht, denn wie Sie sehen können, möchte er die kopierte Liste ändern, ohne einen Effekt auf die Hauptliste zu erzeugen. –

+0

Es macht keinen Sinn, neue Wafer zu erstellen, wenn es ausreicht, die Referenz zu kopieren. – JeffRSon

0

Kurze Antwort: Ja, es ist möglich. Allerdings sollte die Copylist-Methode wie diese

private List<Lot> CopyList(List<Lot> lotList) 
{ 
    List<Lot> result = new List<Lot>(); 

    for (int i = 0; i < lotList.Count; i++) 
    { 
     Lot lot = new Lot(); 
     lot.LotName = lotList[i].LotName; 
     lot.Wafers = new List<Wafer>(lotList[i].Wafers); 
     result.Add(lot); 
    } 

    return result; 
} 

suchen einen neuen lotlist und fügen Sie alle vorhandenen Wafer, um es Dies wird erstellen.

+0

Aber es funktioniert nicht so, wie ich es tat. Wenn ich einen Wafer aus der kopierten Liste entferne, entfernt er ihn auch aus der ursprünglichen Liste: (... –

+0

Es funktioniert nicht. Wenn Sie es in einer Konsolenanwendung kopieren/einfügen, sehen Sie das beschriebene Verhalten. – nmat

+0

@JeffRSon Soweit ich sehen kann ... ist es nicht. – James

7

Ich denke, ich kann sehen, was Ihr Problem hier ist. In Ihrer CopyList klonen Sie effektiv die Liste, d.h.

lot.Wafers = new List<Wafer>(lot.Wafers); 

jedoch der entscheidende Punkt hier zu beachten ist die Referenz zum Lot Objekt ist immer noch die gleich - so effektiv Sie klonen & auch die Wafers Eigenschaft auf der ursprünglichen Liste zu ersetzen.

Wenn Sie

copyList.RemoveAt(1); 

nennen ist das in Ordnung, weil Sie eine Kopie der LotListe manipulieren. Allerdings, wenn Sie anrufen

copyList[0].Wafers.RemoveAt(0); 

Sie ändern die LotInstanz die noch von beiden Listen verwiesen wird. Um das Problem zu lösen, müssten Sie das Lot Objekt selbst klonen, um effektiv die Referenz zu ändern dh

List<Lot> result = new List<Lot>(lotList.Count); 
foreach (Lot item in lotList) 
{ 
    result.Add(new Lot() 
    { 
     LotName = item.LotName, 
     Wafers = new List<Wafer>(item.Wafers) 
    }); 
} 

Als Ergebnis erhalten Sie die automatische Aktualisierung in beiden Listen für die Lot Objekt verlieren würde selbst, aber sie würde es noch behalten für Ändern der einzelnen Objekte Wafer (da die Referenz für sie nicht geändert hätte).

So zusammenzufassen, was Sie effektiv fragen ist:

Wie kann ich das gleiche Objekt Referenz halten, während eine andere Eigenschaft Referenz zu haben?

Die Antwort auf diese Frage ist - Sie können nicht.

+0

Danke! Du hast recht. Das hat meine Augen geöffnet ... –

0

Sie sollten zwei separate Variablen für die Listen verwenden, z. ListLotA und ListLotB. Wenn Sie eine Wafer aus einer Liste entfernen können, ohne sie von einer anderen zu entfernen, und gleichzeitig eine Wafer so anpassen, dass sie sich in beiden Listen widerspiegelt, sollten Sie die Wafer von einer Liste auf die andere kopieren, dh durch Verwendung eines temporären Arrays.

Der Beispielcode unten veranschaulicht dies:

List<Lot> ListLotA = new List<Lot>(); 

Wafer w1 = new Wafer() { WaferName = "w1" }; 
Wafer w2 = new Wafer() { WaferName = "w2" }; 
Wafer w3 = new Wafer() { WaferName = "w3" }; 

ListLotA.Wafers.Add(w1); 
ListLotA.Wafers.Add(w2); 
ListLotA.Wafers.Add(w3); 

List<Lot> ListLotB = new List<Lot>(); 

// At this point adding w1, w2, w3 to the second list is possible, but let's 
// assume it's not and you have to copy them from the first list. 
Wafer[] wArray = new Wafer[ListLotA.Wafers.Count]; 
ListLotA.Wafers.CopyTo(wArray); 

ListLotB.Wafers.AddRange(wArray); 

ListLotA und ListLotB sind separate Objekte, z.B. Sie haben unterschiedliche Referenzen, aber die Liste der einzelnen Wafer hat die gleiche Referenz.

ListLotB.Wafers[1].WaferName = "New Value"; 

Die obige Zeile würde bei Index 1 in ListLotB die Wafer ändern, aber es wäre auch das gleiche Wafer in ListLotA (trotz seines Index) bewirken.

ListLotA.Wafers.Remove(w2); 

Dies würde Wafer entfernen w2 von ListLotA, aber nicht von ListLotB.

Verwandte Themen