【问题标题】:DataContractSerializer requires parameterless constructor in abstract base classDataContractSerializer 需要抽象基类中的无参数构造函数
【发布时间】:2011-09-12 09:58:34
【问题描述】:

当我有以下类并尝试使用DataContractSerializer.WriteObject(..) 序列化ConcreteClass 实例时,我得到一个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:类型 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);
    }
  }
}

【问题讨论】:

  • 您打算如何实例化abstract class?逻辑错误,不计算。
  • 我不打算那样做。当我写“添加public AbstractClass() {}”时,我的意思是将这行代码添加到AbstractClass的代码中
  • 你找到答案了吗?
  • @Omaer 不是真的,除了明显的(在基类中没有带参数的构造函数,使基类中的字段至少受保护且非只读,然后从子构造函数。)
  • @user764754 我最终切换到 Json.Net 只是为了解决这个问题......谢谢!

标签: c# serialization constructor abstract-class datacontractserializer


【解决方案1】:

您得到的异常是 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 属性标记。

【讨论】:

  • 您的解决方案有效。我的问题不是让它以某种方式工作,而是找出抽象基类为什么需要无参数构造函数。我将编辑我的确切代码以使我的问题更清楚。顺便说一句,您不需要这些属性。
  • -1 此答案与问题无关且不正确。与流行的看法相反 - [DataContract] 属性是可选的。缺失时 - DataContractSerializer 会将类的数据协定推断为“该类型的所有公共读/写属性和字段”。见msdn.microsoft.com/en-us/library/ms733127.aspx
猜你喜欢
  • 2017-04-01
  • 1970-01-01
  • 2018-02-27
  • 1970-01-01
  • 1970-01-01
  • 2015-10-15
  • 2021-11-24
  • 2018-07-30
  • 2019-05-12
相关资源
最近更新 更多