在没有序列化的情况下克隆对象

Posted

技术标签:

【中文标题】在没有序列化的情况下克隆对象【英文标题】:Cloning objects without Serialization 【发布时间】:2012-02-14 15:26:33 【问题描述】:

我在 SO 和其他地方找到了许多解决方案,它们通过序列化/反序列化(进入内存并返回)处理对象的深度克隆。

它要求要克隆的类标有[Serializable]。我碰巧将我的类(大部分)标记为[DataContract],因为我使用DataContractSerializer 序列化为XML。

我只介绍了[Serializable] 属性,因为需要对其中一些类实例进行深度克隆。然而,现在通过 DCS 的序列化/反序列化发生了一些事情,因为它不再工作 - 关于在反序列化时期望不同的 XML 元素的错误。如果我删除[Serializable],错误就消失了。

我有哪些选择?我只想尽可能简单地深度克隆我的对象。

【问题讨论】:

您可以使用反射,但这也可能会产生轻微的性能开销。 这里为什么需要[Serializable]?您可以使用 DCS 进行深度克隆...?只需通过 DCS 将其序列化为 MemoryStream...? 是的,我刚刚想出了一些东西,我会发布它 【参考方案1】:

这行得通

    public static T DeepClone<T>(this T a)
    
        using (MemoryStream stream = new MemoryStream())
        
            DataContractSerializer dcs = new DataContractSerializer(typeof(T));
            dcs.WriteObject(stream, a);
            stream.Position = 0;
            return (T)dcs.ReadObject(stream);
        
    

【讨论】:

就像原来的问题一样,这需要用属性标记事物。所以,我看不出这有什么帮助。【参考方案2】:

Json 序列化和反序列化应该可以工作,它不需要类有序列化注释。

public static T DeepCopy<T>(this T source)

    return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(source));

【讨论】:

请注意,它不会克隆私有字段/属性。这是没有 BinaryFormatter ***.com/questions/24106986/… 的另一种方法【参考方案3】:
 public static T Clone<T>(this T o, BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
 
     return (T)CloneObject(o, bindingFlags);
 
 private static object CloneObject(object o, BindingFlags bindingFlags)
 
     if (o is not null)
     
         var type = o.GetType();
         if (type.IsValueType || type == typeof(string))
             return o;

         else if (type.IsArray)
         
             var array = o as Array;
             var elementType = Type.GetType(type.FullName.Replace("[]", string.Empty));
             var instance = Array.CreateInstance(elementType, array.Length);

             for (int i = 0; i < array.Length; i++)
                 instance.SetValue(CloneObject(array.GetValue(i), bindingFlags), i);

             return Convert.ChangeType(instance, type);
         
         else if (type.IsClass)
         
             var instance = Activator.CreateInstance(type);
             var fields = type.GetFields(bindingFlags);

             for (int i = 0; i < fields.Length; i++)
             
                 var value = fields[i].GetValue(o);
                 if (value is not null)
                     fields[i].SetValue(instance, CloneObject(value, bindingFlags));
             
             return instance;
         
     

     return null;
 

【讨论】:

以上是关于在没有序列化的情况下克隆对象的主要内容,如果未能解决你的问题,请参考以下文章

设计模式 -- 原型模式 图解java对象克隆 引用拷贝浅拷贝深拷贝序列化拷贝

设计模式 -- 原型模式 图解java对象克隆 引用拷贝浅拷贝深拷贝序列化拷贝

设计模式 -- 原型模式 图解java对象克隆 引用拷贝浅拷贝深拷贝序列化拷贝

设计模式 -- 原型模式 图解java对象克隆 引用拷贝浅拷贝深拷贝序列化拷贝

如何在没有关系的情况下获取序列化对象

是否可以在 WCF 中没有无参数构造函数的情况下序列化对象?