属性的 DataContractSerializer 反序列化从派生类移动到基类

本文关键字:移动 基类 派生 DataContractSerializer 反序列化 属性 | 更新日期: 2023-09-27 18:33:44

使用DCS,我正在尝试从XML中反序列化对象,其中序列化的对象类型为Child继承类Base,其中Child有一些属性被反序列化,但后来在代码中移动到类Base。现在,这些属性不会被反序列化:

看看这个 XML:

<Base i:type="a:DirectoryEntry" xmlns="http://schemas.datacontract.org/2004/07/pending.Core.Models" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:a="http://schemas.datacontract.org/2004/07/pending.Core.Models.Directory">
    <Active>true</Active>
    <ContentType>DirectoryEntry</ContentType>
    <Created>2012-03-12T11:51:25.3401552+01:00</Created>
    <a:Location>location</a:Location>
    <a:OpenHours>opening</a:OpenHours>
</Base>

XMLNS:A 表示派生的类型名称。这个类曾经持有这些道具。现在它们被移动到基类中,它们不再被 DCS 反序列化(反序列化后属性为 null)。我说的是属性,前面有a:(在这种情况下是位置和开放时间)。

我们有很多这样的文件保存数据。我可以使用哪些选项正确反序列化这些文件?

请注意,[已知类型] 属性在 Base 和 Child 类上使用

属性的 DataContractSerializer 反序列化从派生类移动到基类

将属性移动到基类时,它们实际上移动到另一个 XML 命名空间。基类可能在命名空间pending.Core.Models定义,而派生类在pending.Core.Models.Directory定义(我假设您没有在[DataContract]属性的属性中指定任何内容Namespace。因此,如果您更改了元素应位于的命名空间,则序列化程序将无法将其与您拥有的数据匹配。如果将最后两个属性移动到基类,则需要更改 XML 元素的命名空间 LocationOpenHours

<Base i:type="a:DirectoryEntry"
      xmlns="http://schemas.datacontract.org/2004/07/pending.Core.Models"
      xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:a="http://schemas.datacontract.org/2004/07/pending.Core.Models.Directory">
  <Active>true</Active>
  <ContentType>DirectoryEntry</ContentType>
  <Created>2012-03-12T11:51:25.3401552+01:00</Created>
  <Location>location</Location>
  <OpenHours>opening</OpenHours>
</Base>

我的解决方案是将属性移回原始类,并将它们保留在最初移动到的类中。它现在给出了Property hides the inherited member...Use the new keyword if hiding was intended的警告,但我可以接受,因为反序列化现在再次工作,我们可以将数据从一个提供程序移动到另一个提供程序。我找不到任何其他解决方案,并且无法修改所有序列化数据文件。

正如上面或下面 mare 在接受的答案中提到的,没有解决方案可以在原始类中拥有该属性。但是,通过在原始类的属性声明中使用 new 关键字,可以禁用警告。我最终也得到了以下结构:

[DataContract]
class Base
{
    [DataMember]
    public int X { get; set; }
} 
[DataContract]
class Derived : Base
{
    [DataMember]
    private new int X
    {
        get => base.X;
        set => base.X = value;
    }
}

DataContractSerializer通过反射读取属性,因此它并不真正关心属性是否私有,但将属性放在其原始位置的私有位置会阻止从代码中使用它(按预期)。