Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to remove items in a list of a list without loosing the original reference?

Tags:

c#

.net

Ok this is a little bit hard to ask, but i will try. I have a List with objects (Lots), which contains again a list with objects (Wafers). When i change a value within a wafer it will be changed in both lists! Thats what i want. But when i want to remove a wafer from the copied list, it should not be removed from the orginal list. So i want to have a new List of wafers in each lot but the references to the wafers should be the same as in the original lot because i want to change values to the wafers and it should change the values in the orginal wafer and copied wafer. Is it possible without deep copy?

I have the following code, to explain it better:

    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;
    }

I hope it is not so confusing? And i hope my question is explained good enough.

like image 209
Roman L. Avatar asked May 24 '13 10:05

Roman L.


2 Answers

I think I can see what your issue is here. In your CopyList you effectively clone the list i.e.

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

However, the key point to note here is the reference to the Lot object is still the same - so effectively you are cloning & replacing the Wafers property on the original list as well.

When you call

copyList.RemoveAt(1);

that's fine because you are manipulating a copy of the Lot list. However, when you call

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

you are modifying the Lot instance which is still being referenced by both lists. To solve the problem you would need to clone the Lot object itself to effectively change the reference i.e.

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)
    });
}

As a result you would lose the automatic update in both lists for the Lot object itself but you would still retain it for modifying the individual Wafer objects (as the reference for them wouldn't have changed).

So to summarise, what you are effectively asking is:

How can I keep the same object reference whilst having a different property reference?

The answer to that question is - you can't.

like image 95
James Avatar answered Oct 24 '22 04:10

James


As far as I can see, there is no out-of-the-box way for you to do what you want. Here is a brief description why:

The List<Lot> (far left-hand-side) contains a reference to the Lot object, which in turn contains references to both its member variables.

enter image description here

If you want changes to the LotName and constituents of the Wafers list to be propagated as you describe, the easiest solution is to share a reference to the Lot object between lists:

enter image description here

Now you can see why it is impossible to modify the items in the list of Wafers independently using this solution - you can't get away from the fact that you are using the same object reference!

By sharing a reference you lose the ability to control how differences in behaviour. To achieve what you want, I think you have to do a deep copy of the Lot instances, and you could then manage the propagation of changes through some sort of Observer pattern.

like image 39
Lawrence Avatar answered Oct 24 '22 02:10

Lawrence