How create a new deep copy (clone) of a List<T>?
You need to create new Book
objects then put those in a new List
:
List<Book> books_2 = books_1.Select(book => new Book(book.title)).ToList();
Update: Slightly simpler... List<T>
has a method called ConvertAll
that returns a new list:
List<Book> books_2 = books_1.ConvertAll(book => new Book(book.title));
Create a generic ICloneable<T>
interface which you implement in your Book
class so that the class knows how to create a copy of itself.
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.