如何深度复制类而不将其标记为Serializable
鉴于以下课程:
class A { public List ListB; // etc... }
其中B
是另一个可以inheritance/包含其他类的类。
鉴于这种情况:
-
A
是一个大类,包含许多引用类型 - 我不能将
B
标记为[Serializable]
因为我无法访问B
源代码
以下执行深度复制的方法不起作用:
- 我不能使用
ICloneable
或MemberwiseClone
因为A
类包含许多引用类型 - 我无法为
A
编写复制构造函数,因为该类很大且不断被添加到,并且包含无法深度复制的类(如B
) - 我无法使用序列化,因为我无法将包含的类(如
B
,没有可用的源代码)标记为[Serializable]
我怎样才能深造A
级?
我无论如何都停止使用序列化进行深度复制,因为没有足够的控制(不是每个类都需要以相同的方式复制)。 然后我开始实现自己的深层复制接口,并以应该复制的方式复制每个属性。
复制引用类型的典型方法:
- 使用复制构造函数
- 使用工厂方法(例如,不可变类型)
- 用你自己的“克隆”
- 仅复制引用(例如,其他根类型)
- 创建新实例和复制属性(例如,自己编写的类型缺少复制构造函数)
例:
class A { // copy constructor public A(A copy) {} } // a referenced class implementing class B : IDeepCopy { object Copy() { return new B(); } } class C : IDeepCopy { AA; BB; object Copy() { C copy = new C(); // copy property by property in a appropriate way copy.A = new A(this.A); copy.B = this.B.Copy(); } }
你可能认为这是一项巨大的工作。 但最后,它很简单直接,可以在需要的地方进行调整,并完全满足您的需求。
你可以试试这个。 这个对我有用
public static object DeepCopy(object obj) { if (obj == null) return null; Type type = obj.GetType(); if (type.IsValueType || type == typeof(string)) { return obj; } else if (type.IsArray) { Type elementType = Type.GetType( type.FullName.Replace("[]", string.Empty)); var array = obj as Array; Array copied = Array.CreateInstance(elementType, array.Length); for (int i = 0; i < array.Length; i++) { copied.SetValue(DeepCopy(array.GetValue(i)), i); } return Convert.ChangeType(copied, obj.GetType()); } else if (type.IsClass) { object toret = Activator.CreateInstance(obj.GetType()); FieldInfo[] fields = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); foreach (FieldInfo field in fields) { object fieldValue = field.GetValue(obj); if (fieldValue == null) continue; field.SetValue(toret, DeepCopy(fieldValue)); } return toret; } else throw new ArgumentException("Unknown type"); }
感谢DetoX83关于代码项目的文章 。
private interface IDeepCopy where T : class { T DeepCopy(); } private class MyClass : IDeepCopy { public MyClass DeepCopy() { return (MyClass)this.MemberwiseClone(); } }
Pluss: Yoy可以控制复制过程(如果你的类有标识符属性你可以设置它们,或者你可以编写其他业务逻辑代码)
减:课程可以标记为密封
你不能这样做吗?
[Serializable] class A { ... [NonSerialized] public List ListB; .... }
然后参考如何在.NET中对对象执行深层复制(特别是C#)? 用于克隆function
你的界面IDeepCopy正是ICloneable指定的。
class B : ICloneable { public object Clone() { return new B(); } }
以及更友好的实施:
class B : ICloneable { public B Clone() { return new B(); } // explicit implementation of ICloneable object ICloneable.Clone() { return this.Clone(); } }
尝试使用内存流来获取对象的深层副本:
public static T MyDeepCopy(this T source) { try { //Throw if passed object has nothing if (source == null) { throw new Exception("Null Object cannot be cloned"); } // Don't serialize a null object, simply return the default for that object if (Object.ReferenceEquals(source, null)) { return default(T); } //variable declaration T copy; var obj = new DataContractSerializer(typeof(T)); using (var memStream = new MemoryStream()) { obj.WriteObject(memStream, source); memStream.Seek(0, SeekOrigin.Begin); copy = (T)obj.ReadObject(memStream); } return copy; } catch (Exception) { throw; } }
这是更多。
使用json序列化的另一个线程的答案是我见过的最好的。
public static T CloneJson(this T source) { if (Object.ReferenceEquals(source, null)) { return default(T); } return JsonConvert.DeserializeObject (JsonConvert.SerializeObject(source)); }