1

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

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

我想要列表“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());
        }       

}

4

3 回答 3

6

警告BinaryFormatter当与不受信任的输入一起使用时,该类型很危险。虽然下面的用法应该是安全的,但微软建议BinaryFormatter完全避免,因为它可能被滥用,并将从 .NET 7–8 中删除。考虑为您的深度克隆使用另一种序列化程序或方法。

首先,您可以定义一个实用方法来深度克隆任何对象(根):

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
{
    // …
}
于 2012-05-16T19:22:13.637 回答
4

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

List<SmallClass> newList = new List<SmallClass>();
foreach(var item in myList)
{
    newList.Add((SmallClass)item.Clone());
}
于 2012-05-16T19:10:05.637 回答
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
        }
于 2017-12-18T03:47:47.187 回答