82

次のコードでは、

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;

namespace clone_test_01
{

    public partial class MainForm : Form
    {

        public class Book
        {
            public string title = "";

            public Book(string title)
            {
                this.title = title;
            }
        }


        public MainForm()
        {
            InitializeComponent();

            List<Book> books_1 = new List<Book>();
            books_1.Add(  new Book("One")  );
            books_1.Add(  new Book("Two")  );
            books_1.Add(  new Book("Three")  );
            books_1.Add(  new Book("Four")  );

            List<Book> books_2 = new List<Book>(books_1);

            books_2[0].title = "Five";
            books_2[1].title = "Six";

            textBox1.Text = books_1[0].title;
            textBox2.Text = books_1[1].title;
        }
    }

}

Bookオブジェクトタイプを使用してを作成し、List<T>それに一意のタイトル(「1」から「5」まで)を与えるいくつかのアイテムを入力します。

次に、を作成しますList<Book> books_2 = new List<Book>(books_1)

この時点から、それがリストオブジェクトのクローンであることがわかりますが、book_2からのブックオブジェクトは、のブックオブジェクトからの参照のままですbooks_1books_2これは、の最初の2つの要素に変更を加えてから、の同じ要素をチェックすることで証明されていbook_1ますTextBox

books_1[0].title and books_2[1].title確かにの新しい値に変更されましたbooks_2[0].title and books_2[1].title

今の質問

の新しいハードコピーを作成するにはどうすればよいList<T>ですか?アイデアはそれでbooks_1ありbooks_2、互いに完全に独立するようになります。

私は、MicrosoftがRubyがこのclone()方法で行っているような、きちんとした、速くて簡単なソリューションを提供しなかったことに失望しています。

ヘルパーから本当に素晴らしいのは、私のコードを使用して、コンパイルして機能できるように、実行可能なソリューションでコードを変更することです。この問題に対して提供されている解決策を理解しようとしている初心者にとって、これは本当に役立つと思います。

編集:Bookクラスはより複雑で、より多くのプロパティを持つ可能性があることに注意してください。私は物事をシンプルに保つように努めました。

4

11 に答える 11

124

Book新しいオブジェクトを作成し、それらを new に配置する必要がありますList:

List<Book> books_2 = books_1.Select(book => new Book(book.title)).ToList();

更新:少し単純です...新しいリストを返すList<T>メソッドが呼び出されます:ConvertAll

List<Book> books_2 = books_1.ConvertAll(book => new Book(book.title));
于 2012-12-22T23:20:19.890 に答える
41

クラスに実装する汎用ICloneable<T>インターフェイスを作成Bookして、クラスがそれ自体のコピーを作成する方法を認識できるようにします。

public interface ICloneable<T>
{
    T Clone();
}

public class Book : ICloneable<Book>
{
    public Book Clone()
    {
        return new Book { /* set properties */ };
    }
}

ConvertAllその後、マークが言及したlinqまたはメソッドのいずれかを使用できます。

List<Book> books_2 = books_1.Select(book => book.Clone()).ToList();

また

List<Book> books_2 = books_1.ConvertAll(book => book.Clone());
于 2012-12-22T23:56:22.763 に答える
21

私は、MicrosoftがRubyがこのclone()方法で行っているような、きちんとした、速くて簡単なソリューションを提供しなかったことに失望しています。

深いコピーを作成しないことを除いて、浅いコピーを作成します。

ディープコピーでは、何を正確にコピーするかを常に注意する必要があります。考えられる問題の例は次のとおりです。

  1. オブジェクトグラフを循環します。たとえばBookAuthorAuthorには彼ののリストがありBookます。
  2. いくつかの外部オブジェクトへの参照。たとえば、オブジェクトStreamには、ファイルに書き込むopenが含まれている可能性があります。
  3. イベント。オブジェクトにイベントが含まれている場合、ほとんどの人がそのイベントにサブスクライブできます。サブスクライバーがGUIのようなものである場合、これは特に問題になる可能性がありますWindow

さて、何かを複製する方法は基本的に2つあります。

  1. Clone()複製が必要な各クラスにメソッドを実装します。ICloneable(インターフェースもありますが、使用しないICloneable<T>でください。Trevorが提案したカスタムインターフェースを使用しても問題ありません。)必要なのは、このクラスの各フィールドの浅いコピーを作成することだけであることがわかっている場合は、MemberwiseClone()それを実装するために使用できます。 。別の方法として、「コピーコンストラクター」を作成することもできますpublic Book(Book original)
  2. シリアル化を使用してオブジェクトをにシリアル化しMemoryStream、次にそれらを逆シリアル化します。これには、各クラスをとしてマークする必要があります[Serializable]。また、正確に(そしてどのように)シリアル化する必要があるかを構成することもできます。しかし、これは「迅速で汚い」ソリューションであり、パフォーマンスが低下する可能性があります。
于 2012-12-23T00:19:14.263 に答える
2

は Book のオブジェクト インスタンスを返すためClone、呼び出す前にまずそのオブジェクトを Book にキャストする必要がありますToList。上記の例は、次のように記述する必要があります。

List<Book> books_2 = books_1.Select(book => (Book)book.Clone()).ToList();
于 2014-10-01T21:29:00.330 に答える
0

Array クラスがニーズを満たしている場合は、要素を新しい配列にコピーする List.ToArray メソッドを使用することもできます。

参照: http://msdn.microsoft.com/en-us/library/x303t819(v=vs.110).aspx

于 2015-01-15T15:12:53.417 に答える