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

有什么简单的办法吗?


当前回答

您可以使用扩展方法:

namespace extension
{
    public class ext
    {
        public static List<double> clone(this List<double> t)
        {
            List<double> kop = new List<double>();
            int x;
            for (x = 0; x < t.Count; x++)
            {
                kop.Add(t[x]);
            }
            return kop;
        }
   };

}

你可以通过使用它们的值类型成员来克隆所有对象,例如,考虑这个类:

public class matrix
{
    public List<List<double>> mat;
    public int rows,cols;
    public matrix clone()
    { 
        // create new object
        matrix copy = new matrix();
        // firstly I can directly copy rows and cols because they are value types
        copy.rows = this.rows;  
        copy.cols = this.cols;
        // but now I can no t directly copy mat because it is not value type so
        int x;
        // I assume I have clone method for List<double>
        for(x=0;x<this.mat.count;x++)
        {
            copy.mat.Add(this.mat[x].clone());
        }
        // then mat is cloned
        return copy; // and copy of original is returned 
    }
};

注意:如果你在复制(或克隆)上做了任何改变,它不会影响原始对象。

其他回答

public static object DeepClone(object obj) 
{
    object objResult = null;

    using (var ms = new MemoryStream())
    {
        var bf = new BinaryFormatter();
        bf.Serialize(ms, obj);

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

     return objResult;
}

这是用c#和。net 2.0实现的一种方法。你的对象必须是[Serializable()]。我们的目标是丢失所有的引用,并建立新的引用。

对于深度复制,ICloneable是正确的解决方案,但这里有一个类似的ICloneable方法,使用构造函数而不是ICloneable接口。

public class Student
{
  public Student(Student student)
  {
    FirstName = student.FirstName;
    LastName = student.LastName;
  }

  public string FirstName { get; set; }
  public string LastName { get; set; }
}

// wherever you have the list
List<Student> students;

// and then where you want to make a copy
List<Student> copy = students.Select(s => new Student(s)).ToList();

您需要在以下库中进行复制

using System.Linq

你也可以用for循环代替System。Linq,但是Linq使它简洁干净。同样地,你也可以像其他答案所建议的那样,创建扩展方法等等,但这些都不是必需的。

public static Object CloneType(Object objtype)
{
    Object lstfinal = new Object();

    using (MemoryStream memStream = new MemoryStream())
    {
        BinaryFormatter binaryFormatter = new BinaryFormatter(null, new StreamingContext(StreamingContextStates.Clone));
        binaryFormatter.Serialize(memStream, objtype); memStream.Seek(0, SeekOrigin.Begin);
        lstfinal = binaryFormatter.Deserialize(memStream);
    }

    return lstfinal;
}

没有必要将类标记为Serializable,在我们的测试中,使用Newtonsoft JsonSerializer甚至比使用BinaryFormatter更快。扩展方法可用于每个对象。

注意:私有成员不克隆

标准的。net JavascriptSerializer选项:

public static T DeepCopy<T>(this T value)
{
    JavaScriptSerializer js = new JavaScriptSerializer();

    string json = js.Serialize(value);

    return js.Deserialize<T>(json);
}

使用Newtonsoft JSON更快的选项:

public static T DeepCopy<T>(this T value)
{
    string json = JsonConvert.SerializeObject(value);

    return JsonConvert.DeserializeObject<T>(json);
}

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

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实例。

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