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 つのリスト) に影響するのはなぜですか? と

  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 の項目の順序を変更すると、List2 の項目にも反映されます。これは同じオブジェクトであるためです。

ToList も List コンストラクターもディープ コピーを作成しません。

オブジェクトもコピーする場合は、それらもコピーして、新しい参照を作成して新しいリストに追加する必要があります。.NET では、通常、メソッドICloneable<T>を提供するために実装しますClone。必要ないと思われる場合は、新しいItemを作成してそのプロパティをコピーするだけです。

于 2013-02-07T19:30:37.210 に答える
1

リスト内のオブジェクトを複製する必要があります。それ以外の場合、新しいリストを作成すると、それらはすべて同じオブジェクトを指します。

var listToClone = new List<Item>();

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

3 つの個別のリストがあるため、それらのリストの編集 (つまり、リストへの新しいアイテムの追加、アイテムの削除、特定の位置への新しいアイテムの設定) は、他の変数に影響を与えない変更です。

ただし、各リストのアイテムには実際のItemインスタンスへの参照のみが含まれており、3 つのリストすべてに同じ 3 つの参照があります。そのリストによって参照されているアイテムを変更すると、他のリストから「見える」変更が行われます。

この動作が見られないようにするには、新しいリストを作成するだけでなく、新しいリスト内の項目が、たまたま同じ値を含む新しいオブジェクトへのまったく新しい参照であることを確認する必要があります。一般に、これは簡単な作業ではなく、望ましいことでもありません。

于 2013-02-07T19:33:06.480 に答える
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 に答える