6

鉴于以下代码:

public class Item
{
    private int _id;
    private int _order;
    private string _name;

    public int Id
    {
        get { return _id; }
        set { _id = value; }
    }

    public int Order
    {
        get { return _order; }
        set { _order = value; }
    }

    public string Name
    {
        get { return _name; }
        set { _name = value; }
    }

    public static IList<Item> InitList1()
    {
        var list = new List<Item>
        {
            new Item { Id = 1, Order = 1, Name = "Alpha" },
            new Item { Id = 2, Order = 2, Name = "Bravo" },
            new Item { Id = 3, Order = 3, Name = "Charlie" },
            new Item { Id = 4, Order = 4, Name = "Delta" }
        };

        return list;
    }
}

class Program
{
    static void Main(string[] args)
    {
        // Initialize the lists
        IList<Item> list1 = Item.InitList1();
        IList<Item> list2 = list1.ToList();
        IList<Item> list3 = new List<Item>(list1);

        // Modify list2
        foreach (Item item in list2)
            item.Order++;

        // Modify list3
        foreach (Item item in list3)
            item.Order++;

        // Output the lists
        Console.WriteLine(string.Format("\nList1\n====================="));
        foreach (Item item in list1)
            Console.WriteLine(string.Format("Item - id: {0} order: {1} name: {2}", item.Id, item.Order, item.Name));

        Console.WriteLine(string.Format("\nList2\n====================="));
        foreach (Item item in list2)
            Console.WriteLine(string.Format("Item - id: {0} order: {1} name: {2}", item.Id, item.Order, item.Name));

        Console.WriteLine(string.Format("\nList3\n====================="));
        foreach (Item item in list3)
            Console.WriteLine(string.Format("Item - id: {0} order: {1} name: {2}", item.Id, item.Order, item.Name));

        Console.Write("\nAny key to exit...");
        Console.ReadKey();
    }
}

输出将是:

List1
=====================
Item - id: 1 order: 3 name: Alpha
Item - id: 2 order: 4 name: Bravo
Item - id: 3 order: 5 name: Charlie
Item - id: 4 order: 6 name: Delta


List2
=====================
Item - id: 1 order: 3 name: Alpha
Item - id: 2 order: 4 name: Bravo
Item - id: 3 order: 5 name: Charlie
Item - id: 4 order: 6 name: Delta

List3
=====================
Item - id: 1 order: 3 name: Alpha
Item - id: 2 order: 4 name: Bravo
Item - id: 3 order: 5 name: Charlie
Item - id: 4 order: 6 name: Delta

Any key to exit...

有人可以向我解释一下:

  1. 为什么在创建新列表(list2 和 list3)之后,这些列表上的操作会影响 list1(以及随后的另外两个列表)?和

  2. 如何在不影响 list1 的情况下创建 list1 的新实例并对其进行修改?

4

5 回答 5

11

你实际上得到了一个“浅拷贝”。是的,列表被复制了,但它们仍然指向原始项目。

像这样想。列表实际上并不包含它所包含的项目,而是对它有一个引用。因此,当您复制列表时,新列表仅包含对原始项目的引用。你需要的是这样的

IList newlist = new List<Item>();
foreach(item anItem in myList)
{
     newList.Add(item.ReturnCopy());
}

返回副本看起来像这样:

public Item ReturnCopy()
{
    Item newItem = new Item();

    newItem._id = _id;
    newItem._order = _order;
    newItem._name = _name;
    return newItem

}

这将复制项目中的所有数据,但保持原始数据不变。有很多模式和接口可以提供更好的实现,但我只是想让你了解一下它是如何工作的。

于 2013-02-07T19:33:46.967 回答
4

您有 3 个列表,但它们包含相同的 4 个元素(即对内存中相同的 3 个对象的引用)。因此,当您在 List1 中的某个项目中修改 order 时,它也会在 List2 中的项目中生效 - 因为它是同一个对象。

ToList 和 List 构造函数都不会进行深层复制。

如果您也想复制对象,则还需要复制它们,以创建新引用以添加到新列表中。在 .NET 中,您通常会实现ICloneable<T>以提供Clone方法。如果您觉得不需要,您可以创建 newItem并复制它们的属性。

于 2013-02-07T19:30:37.210 回答
1
static class Extension
{
    public static IList<T> Clone<T>(this IList<T> list) where T: ICloneable
    {
        return list.Select(i => (T)i.Clone()).ToList();
    }
}

现在你可以IList<T>.Clone()用来返回对象了。

于 2013-02-07T19:32:00.960 回答
1

您需要克隆列表中的对象。否则,您将创建新列表,它们都指向相同的对象。

var listToClone = new List<Item>();

var clonedList = listToClone.Select(item => (Item)item.Clone()).ToList();
于 2013-02-07T19:32:46.353 回答
1

您有 3 个不同的列表,因此编辑这些列表(即向列表中添加新项目、删除项目、在给定位置设置新项目)是不会影响其他变量的更改。

但是,每个列表中的项目仅包含对实际Item实例的引用,并且所有三个列表都具有相同的三个引用。当您更改该列表引用的项目时,您所做的更改在其他列表中是“可见的”。

为了不看到这种行为,您不仅需要创建一个新列表,还需要确保新列表中的项目是对恰好包含相同值的新对象的全新引用。在一般情况下,这不是一项微不足道的任务,也不是经常需要的。

于 2013-02-07T19:33:06.480 回答