Nice programing

목록의 새 전체 복사본 (복제본)을 만드는 방법

nicepro 2020. 12. 6. 22:02
반응형

목록의 새 전체 복사본 (복제본)을 만드는 방법?


다음 코드에서

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>나는 몇 가지 항목 ( '오'로 '하나'에서) 그들에게 독특한 제목을주는 채 웁니다.

그런 다음 List<Book> books_2 = new List<Book>(books_1).

이 시점에서 나는 그것이 목록 객체의 복제본이라는 것을 알고 있지만 책 객체 book_2는 여전히 .NET의 책 객체 의 참조입니다 books_1. 그것은 두 첫 번째 요소에 변경하여 입증 books_2하고의 그 같은 요소 확인 book_1A의를 TextBox.

books_1[0].title and books_2[1].title실제로의 새 값으로 변경되었습니다 books_2[0].title and books_2[1].title.

이제 질문

의 새 하드 카피를 어떻게 만듭니 List<T>까? 아이디어는 점이다 books_1books_2서로 완전히 독립적이된다.

나는 마이크로 소프트가 Ruby가 clone()방법 으로하는 것처럼 깔끔하고 빠르고 쉬운 솔루션을 제공하지 않았다는 것에 실망한다 .

도우미에게 정말 멋진 것은 내 코드를 사용하고 실행 가능한 솔루션으로 변경하여 컴파일 및 작동 할 수 있도록하는 것입니다. 이 문제에 대해 제공된 솔루션을 이해하려는 초보자에게 진정으로 도움이 될 것이라고 생각합니다.

편집 : Book클래스가 더 복잡하고 더 많은 속성을 가질 수 있습니다. 나는 일을 단순하게 유지하려고 노력했다.


Book개체를 만든 다음 개체에 넣어야합니다 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));

클래스가 자신의 복사본을 만드는 방법을 알 수 있도록 클래스 ICloneable<T>에서 구현 하는 일반 인터페이스 Book를 만듭니다.

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

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

You can then use either the linq or ConvertAll methods that Mark mentioned.

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

or

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

I'm disappointed Microsoft didn't offer a neat, fast and easy solution like Ruby are doing with the clone() method.

Except that does not create a deep copy, it creates a shallow copy.

With deep copying, you have to be always careful, what exactly do you want to copy. Some examples of possible issues are:

  1. Cycle in the object graph. For example, Book has an Author and Author has a list of his Books.
  2. Reference to some external object. For example, an object could contain open Stream that writes to a file.
  3. Events. If an object contains an event, pretty much anyone could be subscribed to it. This can get especially problematic if the subscriber is something like a GUI Window.

Now, there are basically two ways how to clone something:

  1. Implement a Clone() method in each class that you need cloned. (There is also ICloneable interface, but you should not use that; using a custom ICloneable<T> interface as Trevor suggested is okay.) If you know that all you need is to create a shallow copy of each field of this class, you could use MemberwiseClone() to implement it. As an alternative, you could create a “copy constructor”: public Book(Book original).
  2. Use serialization to serialize your objects into a MemoryStream and then deserialize them back. This requires you to mark each class as [Serializable] and it can also be configured what exactly (and how) should be serialized. But this is more of a “quick and dirty” solution, and will most likely also be less performant.

List<Book> books_2 = new List<Book>(books_2.ToArray());

That should do exactly what you want. Demonstrated here.


Well,

If you mark all involved classes as serializable you can :

public static List<T> CloneList<T>(List<T> oldList)  
{  
BinaryFormatter formatter = new BinaryFormatter();  
MemoryStream stream = new MemoryStream();  
formatter.Serialize(stream, oldList);  
stream.Position = 0;  
return (List<T>)formatter.Deserialize(stream);      
} 

Source:

https://social.msdn.microsoft.com/Forums/en-US/5c9b4c31-850d-41c4-8ea3-fae734b348c4/copy-listsomeobject-to-clone-list?forum=csharpgeneral


Since Clone would return an object instance of Book, that object would first need to be cast to a Book before you can call ToList on it. The example above needs to be written as:

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

If the Array class meets your needs, you could also use the List.ToArray method, which copies elements to a new array.

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


public static class Cloner
{
    public static T Clone<T>(this T item)
    {
        FieldInfo[] fis = item.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
        object tempMyClass = Activator.CreateInstance(item.GetType());
        foreach (FieldInfo fi in fis)
        {
            if (fi.FieldType.Namespace != item.GetType().Namespace)
                fi.SetValue(tempMyClass, fi.GetValue(item));
            else
            {
                object obj = fi.GetValue(item);
                if (obj != null)
                    fi.SetValue(tempMyClass, obj.Clone());
            }
        }
        return (T)tempMyClass;
    }
}

You can use this:

var newList= JsonConvert.DeserializeObject<List<Book>>(list.toJson());

참고URL : https://stackoverflow.com/questions/14007405/how-create-a-new-deep-copy-clone-of-a-listt

반응형