我正在尝试使用以下方法创建对象的深层克隆。
public static T DeepClone<T>(this T target)
{
using (MemoryStream stream = new MemoryStream())
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, target);
stream.Position = 0;
return (T)formatter.Deserialize(stream);
}
}
此方法需要一个序列化的对象,即其上具有属性“Serializable”的类的对象。我有一个类,它具有属性“DataContract”,但该方法不使用此属性。我认为“DataContract”也是一种序列化器,但可能与“Serializable”不同。
有谁能请给我两者之间的区别?另请告诉我是否可以创建一个只有1个属性的对象的深度克隆,它可以完成“DataContract”和“Serializable”属性的工作,也可能是创建深度克隆的不同方式?
请帮忙!
答案 0 :(得分:23)
Serializable
需要 BinaryFormatter
才能正常工作。
DataContract
和DataMember
属性与DataContractSerializer
一起使用。
您可以使用两个序列化程序的属性修饰一个类。
答案 1 :(得分:6)
DataContract
用于WCF,因此.NET 3.0+。在.net 2.0或更低版本中,没有DataContract,DataMember
属性,只有Serializable
。
正如Oded所说,如果你想使用BinaryFormatter,你必须用 Serializable 来装饰这个类型。
答案 2 :(得分:2)
我曾经通过Reflection对对象结构进行了一些检查,以找到反序列化所需的所有程序集,并将它们串行化以进行自举。
通过一些工作,可以构建类似的深度复制方法。基本上你需要一个递归方法,沿着Dictionary来检测循环引用。在方法内部,您可以检查所有字段:
private void InspectRecursively(object input,
Dictionary<object, bool> processedObjects)
{
if ((input != null) && !processedObjects.ContainsKey(input))
{
processedObjects.Add(input, true);
List<FieldInfo> fields = type.GetFields(BindingFlags.Instance |
BindingFlags.Public | BindingFlags.NonPublic );
foreach (FieldInfo field in fields)
{
object nextInput = field.GetValue(input);
if (nextInput is System.Collections.IEnumerable)
{
System.Collections.IEnumerator enumerator = (nextInput as
System.Collections.IEnumerable).GetEnumerator();
while (enumerator.MoveNext())
{
InspectRecursively(enumerator.Current, processedObjects);
}
}
else
{
InspectRecursively(nextInput, processedObjects);
}
}
}
}
要使其正常工作,您需要添加一个输出对象和System.Runtime.Serialization.FormatterServices.GetUninitializedObject(Type type)
之类的东西,以创建每个字段值的最浅的副本(即使没有复制引用)。最后,您可以使用field.SetValue(input, output)
但是,此实现不支持已注册的事件处理程序,反序列化也支持_ un _。此外,如果其类的构造函数需要初始化除了设置所有字段之外的任何内容,那么层次结构中的每个对象都将被破坏。最后一点仅适用于序列化,如果该类具有相应的实现,例如标记为[OnDeserialized]
的方法,实现ISerializable
,....