목록의 새 전체 복사본 (복제본)을 만드는 방법?
다음 코드에서
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_1
A의를 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
서로 완전히 독립적이된다.
나는 마이크로 소프트가 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:
- Cycle in the object graph. For example,
Book
has anAuthor
andAuthor
has a list of hisBook
s. - Reference to some external object. For example, an object could contain open
Stream
that writes to a file. - 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:
- Implement a
Clone()
method in each class that you need cloned. (There is alsoICloneable
interface, but you should not use that; using a customICloneable<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 useMemberwiseClone()
to implement it. As an alternative, you could create a “copy constructor”:public Book(Book original)
. - 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:
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
'Nice programing' 카테고리의 다른 글
런타임에 즉시 텍스트에서 이미지를 생성하는 방법 (0) | 2020.12.06 |
---|---|
비공개 github 저장소에서 가져올 gem을 어떻게 지정할 수 있나요? (0) | 2020.12.06 |
TypeError : $ (…) .DataTable은 함수가 아닙니다. (0) | 2020.12.06 |
오류 1053 : 서비스가 시작 또는 제어 요청에 적시에 응답하지 않았습니다. (0) | 2020.12.06 |
Response.Cookies보다 Request.Cookies를 언제 사용합니까? (0) | 2020.12.06 |