深度克隆c#中的对象列表

时间:2012-05-16 19:04:31

标签: c#

我有一个名为“SmallClass”的C#类。

我有一个包含“SmallClass”类型对象的现有列表myList

我想要深度克隆列表“myList”。也就是说,深入克隆包含列表并深度克隆列表中包含的对象。

我该怎么做。

    public class SmallClass: ICloneable {

    public string str1;
    public string str2;
    public string str3;

     public SmallClass Clone() //This just deep clones 1 object of type "SmallClass"
            {
                MemoryStream m = new MemoryStream();
                BinaryFormatter b = new BinaryFormatter();
                b.Serialize(m, this);
                m.Position = 0;
                return (SRO)b.Deserialize(m);
            }

      public override equals(Object a)
        {
                return Object.Equals(this.str1 && a.str1);
            }
    }

    public class AnotherClass
    {
           SomeCode();
           List<SmallClass> myList = new List<SmallList>();  //myList is initialized.


           // NOW I want to deep clone myList. deep Clone the containing list and deep clone the objects contained in the list.

         List<SmallClass> newList = new List<SmallClass>();
      foreach(var item in myList)
        {
           newList.Add((SmallClass)item.Clone());
        }       

}

3 个答案:

答案 0 :(得分:4)

您的SmallClass需要实现ICloneable接口。然后使用Clone()方法复制每个元素。

List<SmallClass> newList = new List<SmallClass>();
foreach(var item in myList)
{
    newList.Add((SmallClass)item.Clone());
}

答案 1 :(得分:4)

首先,您可以定义用于深度克隆任何对象(根)的实用程序方法:

public static T DeepClone<T>(T obj)
{
    using (var stream = new MemoryStream())
    {
        var formatter = new BinaryFormatter();
        formatter.Serialize(stream, obj);
        stream.Position = 0;
        return (T)formatter.Deserialize(stream);
    }
}

如果您想深度克隆myList,您只需将其作为参数传递给上述方法:

List<SmallClass> myListClone = DeepClone(myList);

您需要注意的最重要的考虑因素是,您的所有课程必须标记为可序列化,通常是[SerializableAttribute]

[SerializableAttribute]
public class SmallClass
{
    // …
}

答案 2 :(得分:0)

有几种方法可以创建包含序列化和使用Object.MemberwiseClone Method()的深层副本。由于这里已经提供了使用序列化的示例,我有一种方法是使用“MemberwiseClone”。

注意:递归,平台:.NETStandard2.0

        /// <summary>
        /// Returns a deep copy of an object.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <returns></returns>
        public static T DeepClone<T>(this T source) where T : class
        {
            if(source == null) return null;

            if(source is ICollection<object> col)
            {
                return (T)DeepCloneCollection(col);
            }
            else if(source is IDictionary dict)
            {
                return (T)DeepCloneDictionary(dict);
            }

            MethodInfo method = typeof(object).GetMethod("MemberwiseClone", BindingFlags.NonPublic | BindingFlags.Instance);
            T clone = (T)method.Invoke(source, null);

            foreach(FieldInfo field in source.GetType().GetRuntimeFields())
            {
                if(field.IsStatic) continue;
                if(field.FieldType.GetTypeInfo().IsPrimitive) continue;

                object sourceValue = field.GetValue(source);
                field.SetValue(clone, DeepClone(sourceValue));
            }

            return clone;
        }

        private static ICollection<object> DeepCloneCollection(ICollection<object> col)
        {
            object[] arry = (object[])Activator.CreateInstance(col.GetType(), new object[] { col.Count });

            for(int i = 0; i < col.Count; i++)
            {
                object orig = col.ElementAt(i);
                object cln = DeepClone(orig);

                arry[i] = cln;
            }

            return arry;
        }

        private static IDictionary DeepCloneDictionary(IDictionary dict)
        {
            IDictionary clone = (IDictionary)Activator.CreateInstance(dict.GetType());

            foreach(object pair in dict)
            {
                object key = pair.GetValueOf("Key");
                object original = pair.GetValueOf("Value");

                clone.Add(key, original.DeepClone());
            }

            return clone;
        }

        public static dynamic GetValueOf<T>(this T value, string property)
        {
            PropertyInfo p = value.GetType().GetTypeInfo().GetProperty(property);

            if(p != null && p.CanRead)
            {
                dynamic val = p.GetValue(value);

                return val;
            }

            return Activator.CreateInstance(p.PropertyType); //Property does not have  value, return default
        }