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

use*_*754 5 c# serialization constructor abstract-class datacontractserializer

当我具有以下类并且尝试ConcreteClass使用DataContractSerializer序列化实例时,.WriteObject(..)我得到了一个InvalidDataContractException

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

public class ConcreteClass : AbstractClass
{
  public ConcreteClass() : base("text") {  } 
}
Run Code Online (Sandbox Code Playgroud)

序列化器用实例化new DataContractSerializer(typeof(ConcreteClass)

使用XmlSerializer没问题。

现在,当添加 public AbstractClass() {}

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

那么,为什么DataContractSerializer要求抽象基类具有无参数构造函数?这里说明可以对类型进行序列化,即“具有不带参数的构造函数”,这对于ConcreteClass是正确的。我还向此必需的构造函数中添加了一些代码,而且我认为在序列化过程中从未调用过它。


完整的异常显示:

System.Runtime.Serialization.InvalidDataContractException:类型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);
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

小智 -3

您得到的异常是,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; }
}
Run Code Online (Sandbox Code Playgroud)

如果我尝试序列化我的 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; }
}
Run Code Online (Sandbox Code Playgroud)

现在我们已经能够创建序列化文件了。但是,不会有任何信息,因为我们从未告诉 DataContract 要包含哪些内容。为了解决此问题,我们将 DataMember 属性添加到我们想要包含的类中的属性中。

[DataContract]
public class Foo : Bar
{
    [DataMember]
    string one { get; set; }
    string two { get; set; }
    [DataMember]
    string three { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

通过在序列化此类时添加 DataMember 属性,它将仅序列化有关字符串一和字符串三的信息。字符串二不会被包含,因为它没有专门用 DataMember 属性标记。

  • -1 这个答案与问题无关并且不正确。与流行的看法相反 - [DataContract] 属性是可选的。如果缺少,DataContractSerializer 会将类的数据协定推断为“该类型的所有公共读/写属性和字段”。请参阅http://msdn.microsoft.com/en-us/library/ms733127.aspx (5认同)