views:

23667

answers:

8

I have a generic list of objects in C#, and wish to clone the list. The items within the list are cloneable, but there doesn't seem to be an option to do list.Clone()

Is there an easy way around this?

+1  A: 

Well you can always deepclone

http://www.code-magazine.com/Article.aspx?quickid=0601121

DaveJustDave
+1  A: 

Don't think there is a built in way to do this. I would make an extension on List.

Jim
+1  A: 

For a shallow copy, you can instead use the GetRange method of the generic List class.

List<int> oldList = new List<int>( );
// Populate oldList...

List<int> newList = oldList.GetRange(0, oldList.Count);

Quoted from: Generics Recipes

Anthony Potts
+22  A: 

If your elements are value types, then you can just do:

List<YourType> newList = new List<YourType>(oldList);

However, if they are reference types and you want a deep copy (assuming your elements properly implement ICloneable), you could do something like this:

List<ICloneable> oldList = new List<ICloneable>();
List<ICloneable> newList = new List<ICloneable>(oldList.Count);

oldList.ForEach((item) =>
    {
        newList.Add((ICloneable)item.Clone());
    });

Obviously, replace ICloneable in the above generics and cast with whatever your element type is that implements ICloneable.

If your element type doesn't support ICloneable but does have a copy-constructor, you could do this instead:

List<YourType> oldList = new List<YourType>();
List<YourType> newList = new List<YourType>(oldList.Count);

oldList.ForEach((item)=>
    {
        newList.Add(new YourType(item));
    });

Personally, I would avoid ICloneable because of the need to guarantee a deep copy of all members. Instead, I'd suggest the copy-constructor or a factory method like YourType.CopyFrom(YourType itemToCopy) that returns a new instance of YourType.

Any of these options could be wrapped by a method (extension or otherwise).

Jeff Yates
I think List<T>.ConvertAll might look nicer than creating a new list and doing a foreach+add.
MichaelGG
Good point. I must admit, I'm still coming to grips with all the LINQ calls myself.
Jeff Yates
+1 So in summary, it is impossible to provide a deep clone function for a Generic.List. Is that right?
Dimitri C.
@Dimitri: No, that's not true. The problem is, when `ICloneable` was defined, the definition never stated whether the clone was deep or shallow, so you cannot determine which type of Clone operation will be done when an object implements it. This means that if you want to do a deep clone of `List<T>`, you will have to do it without `ICloneable` to be sure it is a deep copy.
Jeff Yates
+1  A: 

If you know the type:

List<int> newList = new List<int>(oldList);

If you don't know the type before, you'll need a helper function:

List<T> Clone<T>(IEnumerable<T> oldList)
{
    return newList = new List<T>(oldList);
}

The just:

List<string> myNewList = Close(myOldList);
James Curran
This doesn't clone the elements.
Jeff Yates
+9  A: 

You can use an extension method.

static class Extensions
{
 public static IList<T> Clone<T>(this IList<T> listToClone) where T: ICloneable
 {
  return listToClone.Select(item => (T)item.Clone()).ToList();
 }
}
ajm
should there be a space between IList<T> and Clone<T>?
rcreswick
You are right. I edited my answer to fix the code. Thank you for noticing it.
ajm
I think List.ConvertAll might do this in faster time, since it can pre-allocate the entire array for the list, versus having to resize all the time.
MichaelGG
+8  A: 
public static object DeepClone(object obj) 
{
  object objResult = null;
  using (MemoryStream  ms = new MemoryStream())
  {
    BinaryFormatter  bf =   new BinaryFormatter();
    bf.Serialize(ms, obj);

    ms.Position = 0;
    objResult = bf.Deserialize(ms);
  }
  return objResult;
}

This is one way to do it with C# and framework 2.0. Your object require to be [Serializable()]... This method Serialize and unserialize. The goal is to lost all reference and build new one.

Daok
+1 - i like this answer - it is quick, dirty, nasty and very effective. I used in silverlight, and used the DataContractSerializer as the BinarySerializer was not available. Who needs to write pages of object cloning code when you can just do this? :)
slugster