6

好的,这有点难问,但我会尝试的。我有一个带有对象(Lots)的列表,其中再次包含一个带有对象(Wafer)的列表。当我更改晶圆中的值时,两个列表中的值都会更改!这就是我想要的。但是当我想从复制列表中删除一个晶圆时,它不应该从原始列表中删除。所以我想在每个批次中都有一个新的晶圆列表,但是对晶圆的引用应该与原始批次中的相同,因为我想更改晶圆的值,它应该更改原始晶圆和复制晶圆中的值. 没有深拷贝有可能吗?

我有以下代码,可以更好地解释它:

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

我希望它不会那么混乱?我希望我的问题得到足够的解释。

4

5 回答 5

7

我想我可以在这里看到您的问题。在您的CopyList有效克隆列表中,即

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

但是,这里要注意的关键点是对对象的引用Lot仍然是相同的 - 因此,您也可以有效地克隆和替换Wafers原始列表上的属性。

你打电话时

copyList.RemoveAt(1);

Lot 这很好,因为您正在操作list的副本。然而,当你打电话

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

您正在修改两个列表仍在引用的Lot 实例。要解决该问题,您需要克隆Lot对象本身以有效更改引用,即

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

结果,您将失去Lot对象本身在两个列表中的自动更新,但您仍会保留它以修改各个Wafer对象(因为它们的引用不会改变)。

总而言之,您实际上要问的是:

如何在具有不同属性引用的同时保留相同的对象引用?

这个问题的答案是——你不能。

于 2013-05-24T12:14:27.453 回答
4

据我所知,没有开箱即用的方式让你做你想做的事。下面简要说明原因:

List<Lot>最左侧)包含对对象的引用,该Lot对象又包含对其两个成员变量的引用。

在此处输入图像描述

如果您希望按照您的描述传播LotName对列表的和成分的更改,最简单的解决方案是在列表之间共享对对象的引用:WafersLot

在此处输入图像描述

现在您可以看到为什么无法Wafers独立使用此解决方案修改列表中的项目 - 您无法摆脱使用相同对象引用的事实!

通过共享参考,您将失去控制行为差异的能力。为了实现您想要的,我认为您必须对Lot实例进行深层复制,然后您可以通过某种观察者模式管理更改的传播。

于 2013-05-24T12:06:45.137 回答
0

您应该为列表使用两个单独的变量,例如ListLotAListLotB。如果您希望能够从一个列表中删除 aWafer而不会从另一个列表中删除它,同时调整 aWafer以使其反映在两个列表中,您应该将 Wafer 从一个列表复制到另一个列表,即使用 a临时数组。

下面的示例代码说明了这一点:

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并且ListLotB是单独的对象,例如它们具有不同的引用,但各个晶圆的列表具有相同的引用。

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

上述行将更改 ListLotB 中索引 1 处的 Wafer,但它也会影响 ListLotA 中的相同 Wafer(尽管它的索引)。

ListLotA.Wafers.Remove(w2);

这将从 ListLotA 中删除 Wafer w2,但不会从 ListLotB 中删除。

于 2013-05-24T13:01:41.790 回答
0

简短的回答:是的,这是可能的。但是,CopyList 方法应如下所示

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

这将创建一个新的批次清单并将所有现有的晶圆添加到其中。

于 2013-05-24T11:09:36.270 回答
0

问题是您通过维护对主列表的引用来创建克隆列表。你应该使用类似的东西:

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;
}
于 2013-05-24T10:52:28.393 回答