我在c#中有一个对象的通用列表,并希望克隆列表。列表中的项是可克隆的,但似乎没有做list. clone()的选项。

有什么简单的办法吗?


当前回答

如果你的元素是值类型,那么你可以这样做:

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

然而,如果它们是引用类型,并且你想要一个深度拷贝(假设你的元素正确地实现了ICloneable),你可以这样做:

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

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

显然,要替换上面泛型中的ICloneable,并使用实现ICloneable的元素类型进行强制转换。

如果你的元素类型不支持ICloneable,但是有一个复制构造函数,你可以这样做:

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

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

就我个人而言,我会避免使用ICloneable,因为需要保证所有成员的深度副本。相反,我建议使用复制构造函数或类似YourType的工厂方法。CopyFrom(YourType itemToCopy)返回一个新的YourType实例。

这些选项中的任何一个都可以通过方法(扩展或其他方式)包装。

其他回答

我已经为我自己做了一些扩展,它转换了ICollection的项目,没有实现IClonable

static class CollectionExtensions
{
    public static ICollection<T> Clone<T>(this ICollection<T> listToClone)
    {
        var array = new T[listToClone.Count];
        listToClone.CopyTo(array,0);
        return array.ToList();
    }
}
    public List<TEntity> Clone<TEntity>(List<TEntity> o1List) where TEntity : class , new()
    {
        List<TEntity> retList = new List<TEntity>();
        try
        {
            Type sourceType = typeof(TEntity);
            foreach(var o1 in o1List)
            {
                TEntity o2 = new TEntity();
                foreach (PropertyInfo propInfo in (sourceType.GetProperties()))
                {
                    var val = propInfo.GetValue(o1, null);
                    propInfo.SetValue(o2, val);
                }
                retList.Add(o2);
            }
            return retList;
        }
        catch
        {
            return retList;
        }
    }
public class CloneableList<T> : List<T>, ICloneable where T : ICloneable
{
  public object Clone()
  {
    var clone = new List<T>();
    ForEach(item => clone.Add((T)item.Clone()));
    return clone;
  }
}

对于浅拷贝,您可以使用泛型List类的GetRange方法。

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

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

引用自:generic Recipes

对于深度克隆,我使用反射如下:

public List<T> CloneList<T>(IEnumerable<T> listToClone) {
    Type listType = listToClone.GetType();
    Type elementType = listType.GetGenericArguments()[0];
    List<T> listCopy = new List<T>();
    foreach (T item in listToClone) {
        object itemCopy = Activator.CreateInstance(elementType);
        foreach (PropertyInfo property in elementType.GetProperties()) {
            elementType.GetProperty(property.Name).SetValue(itemCopy, property.GetValue(item));
        }
        listCopy.Add((T)itemCopy);
    }
    return listCopy;
}

你可以交替使用List或IEnumerable。