.NET序列化排序

Chr*_*ght 14 c# xml serialization xml-serialization

我试图使用XmlSerializer和继承序列化一些对象,但我在排序结果时遇到了一些问题.

下面是一个类似于我设置的示例:〜

public class SerializableBase
{
    [XmlElement(Order = 1)]
    public bool Property1 { get; set;}

    [XmlElement(Order = 3)]
    public bool Property3 { get; set;}
}

[XmlRoot("Object")]
public class SerializableObject1 : SerializableBase
{
}

[XmlRoot("Object")]
public class SerializableObject2 : SerializableBase
{
    [XmlElement(Order = 2)]
    public bool Property2 { get; set;}
}
Run Code Online (Sandbox Code Playgroud)

我想要的结果如下:〜

<Object>
    <Property1></Property1>
    <Property2></Property2>
    <Property3></Property3>
</Object>
Run Code Online (Sandbox Code Playgroud)

但是我得到的结果是:〜

<Object>
    <Property1></Property1>
    <Property3></Property3>
    <Property2></Property2>
</Object>
Run Code Online (Sandbox Code Playgroud)

有谁知道它是否可能或任何替代方案?

谢谢

Nad*_*zie 19

从技术上讲,从纯xml的角度来看,我想说这可能是一件坏事.

.NET隐藏了XmlSerialization之类的复杂功能 - 在这种情况下,它隐藏了序列化xml应符合的模式.

推断的模式将使用序列元素来描述基类型和扩展类型.这需要严格的排序 - 即使反序列化器不那么严格并且接受乱序元素.

在xml架构中,在定义扩展类型时,子类中的其他元素必须位于基类的元素之后.

你本质上有一个类似的架构(为清楚起见,删除了xml-y标签)

base
  sequence
    prop1
    prop3

derived1 extends base
  sequence
    <empty>

derived2 extends base
  sequence
    prop2
Run Code Online (Sandbox Code Playgroud)

没有办法在prop1和prop3之间插入占位符来指示派生xml的属性可以去哪里.

最后,您的数据格式与业务对象之间存在不匹配.可能你最好的选择是定义一个对象来处理你的xml序列化.

例如

[XmlRoot("Object")
public class SerializableObjectForPersistance
{
    [XmlElement(Order = 1)]
    public bool Property1 { get; set; }

    [XmlElement(Order = 2, IsNullable=true)]
    public bool Property2 { get; set; }

    [XmlElement(Order = 3)]
    public bool Property3 { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

这会将xml序列化代码与对象模型分开.将SerializableObject1或SerializableObject2中的所有值复制到SerializableObjectForPersistance,然后将其序列化.

从本质上讲,如果您希望对序列化xml的格式进行这样的特定控制,而这种格式与期望的xml序列化框架不相符,那么您需要解耦业务对象设计(在这种情况下为继承结构)以及序列化的责任.业务对象.


Ste*_*per 5

编辑:这种方法不起作用。我已经离开了帖子,以便人们可以避免这种想法。

序列化程序以递归方式执行。这样做有好处;在反序列化时,反序列化过程可以读取基类,然后是派生类。这意味着派生类的属性没有在基类的属性之前设置,这可能会导致问题。

如果这真的很重要(我不确定为什么按顺序排列这些很重要)那么你可以试试这个——

1) 使基类的 Property1 和 Property3 成为虚拟的。2) 用派生类中的琐碎属性覆盖它们。例如

public class SerializableBase
{
    [XmlElement(Order = 1)]
    public virtual bool Property1 { get; set;}

    [XmlElement(Order = 3)]
    public virtual bool Property3 { get; set;}
}

[XmlRoot("Object")]
public class SerializableObject1 : SerializableBase
{
}

[XmlRoot("Object")]
public class SerializableObject2 : SerializableBase
{
    [XmlElement(Order = 1)]
    public override bool Property1 
    { 
      get { return base.Property1; }
      set { base.Property1 = value; }
    }

    [XmlElement(Order = 2)]
    public bool Property2 { get; set;}

    [XmlElement(Order = 3)]
    public override bool Property3
    { 
      get { return base.Property3; }
      set { base.Property3 = value; }
    }

}
Run Code Online (Sandbox Code Playgroud)

这将属性的具体实现放在最派生的类上,并且应该遵守顺序。


jjx*_*tra 3

看起来 XmlSerializer 类序列化基类型,然后按该顺序序列化派生类型,并且仅单独尊重每个类中的 Order 属性。即使顺序不完全是您想要的,它仍然应该正确反序列化。如果您确实必须有这样的顺序,您将需要编写一个自定义 xml 序列化程序。我会警告您不要这样做,因为 .NET XmlSerializer 为您做了很多特殊处理。您能描述一下为什么您需要按照您提到的顺序进行操作吗?