.net中DataContract属性和Serializable属性之间的区别

时间:2010-12-28 10:44:57

标签: c# .net serialization clone

我正在尝试使用以下方法创建对象的深层克隆。

    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”属性的工作,也可能是创建深度克隆的不同方式?

请帮忙!

3 个答案:

答案 0 :(得分:23)

Serializable需要

BinaryFormatter才能正常工作。

DataContractDataMember属性与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,....