DataContractSerializer在抽象基类中需要无参数构造函数

时间:2011-06-10 10:52:07

标签: c# serialization constructor abstract-class datacontractserializer

如果我有以下课程,并尝试使用DataContractSerializer ConcreteClass序列化.WriteObject(..)个实例,我会收到InvalidDataContractException

public abstract class AbstractClass
{            
  protected AbstractClass(string text) { }
}

public class ConcreteClass : AbstractClass
{
  public ConcreteClass() : base("text") {  } 
}

使用new DataContractSerializer(typeof(ConcreteClass)实例化序列化程序。

使用XmlSerializer没有任何问题。

现在添加 public AbstractClass() {}

两个序列化器都可以工作。

那么为什么DataContractSerializer需要抽象基类来拥有无参数的构造函数呢? Here声明类型可以序列化,“具有一个没有参数的构造函数”,这对于ConcreteClass来说是正确的。我还为这个必需的构造函数添加了一些代码,我认为它不会在序列化过程中被调用。


完整的异常说:

  

System.Runtime.Serialization.InvalidDataContractException:Type   AbstractClass'无法序列化。考虑用它标记它   DataContractAttribute属性,并标记其所有成员   想要使用DataMemberAttribute属性进行序列化。见   其他受支持类型的Microsoft .NET Framework文档。

如果我离开无参数构造函数并使用建议的属性,它甚至可以工作。那么为什么会有一个区别,为什么会尝试序列化一个抽象类呢?当然,抽象类中可能存在类似属性的东西但是不应该将它们与ConcreteClass实例(继承这些东西)一起序列化?

修改

我的确切代码:

namespace SerilizationTest
{
  public abstract class AbstractClass
  {
    public string StringProperty { get; set; }

    //This constructor is required (although never called).
    //If not present we get "InvalidDataContractException :
    //Type AbstractClass cannot be serialized"
    public AbstractClass()
    {
      Console.WriteLine("We won't see this.");
    }

    public AbstractClass(string text)
    {
      StringProperty = text;
    }
  }

  public class ConcreteClass : AbstractClass
  {
    public ConcreteClass() : base("text") { }
  }

  class Program
  {
    static void Main()
    {
      var serializer = new DataContractSerializer(typeof(ConcreteClass));
      var memStream = new MemoryStream();
      serializer.WriteObject(memStream, new ConcreteClass());
      memStream.Seek(0, SeekOrigin.Begin);
      var deserializedObj = (ConcreteClass)serializer.ReadObject(memStream);
      Console.WriteLine(deserializedObj.StringProperty);
    }
  }
}

1 个答案:

答案 0 :(得分:-2)

您得到的异常是说AbstractClass上没有[DataContract]属性。

DataContract是一个用于标记可序列化类的属性。如果您通过使用DataMember属性告诉它,则此属性将仅包括要序列化的类中的属性。

DataMember属性用于标记可序列化类中所需的属性。

此属性位于System.Runtime.Serialization;

例如......

public abstract class Bar
{
}

public class Foo : Bar
{
    string one { get; set; }
    string two { get; set; }
    string three { get; set; }
}

如果我尝试序列化我的Foo类,那么我将得到你的例外。因此,如果我将DataContract属性添加到我的Bar类,就像异常建议下次我尝试序列化时,我会得到相同的错误,只是指向我的代码的另一部分,即Foo类本身。 我需要做的就是像这样添加DataContract。

[DataContract]
public abstract class Bar
{
}

[DataContract]
public class Foo : Bar
{
    string one { get; set; }
    string two { get; set; }
    string three { get; set; }
}

现在我们所拥有的将能够创建一个序列化文件。但是,没有任何信息,因为我们从未告诉我们DataContract要包含什么。为了解决这个问题,我们将DataMember属性添加到我们想要包含的类中的属性。

[DataContract]
public class Foo : Bar
{
    [DataMember]
    string one { get; set; }
    string two { get; set; }
    [DataMember]
    string three { get; set; }
}

在序列化此类时添加了DataMember属性,它只会序列化有关字符串1和字符串3的信息。不包括字符串2,因为它没有专门用DataMember属性标记。