使用变体子项反序列化 XML

Deserialize XML with variant child

我有一个设备可以通过 TCP 随机生成 6 种不同类型的 XML 通知。我已经成功反序列化通知;但是,对于 1 个特定的通知、事件,我需要一些关于如何更有效地处理它的建议。

以下是事件通知的 3/36 示例:

Example 1
<event>
  <property1>721695632</property1>
  <property2>266</property2>
  <class1>
   <property31>dirk</property31>
   <property32>192.168.1.110</property32>
   <property33>fx</property33>
  </class1>
</event>  

Example 2
<event>
  <property1>721555130</property1>
  <property2>263</property2>
  <class2>
    <property41>00-00-00-00-00-00-00-00</property41>
    <property42>569</property42>
  </class2>
</event>

Example 3
<event>
 <property1>724342931</property1>
 <property2>326</property2>
 <class3>
  <property51>23</property51>
  <property52>00-00-00-00-00-00-00-02</property52>
  <property53>100.00</property53>
  <property54>0000AF72B7C12094EE833326234</property54>
 </class3>
</event>

事件通知之间的唯一共同点是根节点以及 属性1 和 属性2 节点。其余节点因不同事件而异。为了反序列化事件通知,我创建了以下 classes:

public class Event
{
    public ulong Property1 {get; set;}
    public int Property2 {get; set;}

    public class1 Property3 {get; set;}
    public class2 Property4 {get; set;}
    public class3 Property5 {get; set;}

}

public class1 
{   
    public string Property31 {get; set;}
    public string Property32 {get; set;}
    public string Property32 {get; set;}
}

public class2 
{   
    public string Property41 {get; set;}
    public int Property42 {get; set;}
}

public class3
{   
    public int Property51 {get; set;}
    public string Property52 {get; set;}
    public double Property53 {get; set;}
    public string Property54 {get; set;}
}

我使用事件 class 反序列化事件通知。反序列化后,我循环遍历事件 class 中的所有属性以搜索属性 != null。总是有 3 个非空属性。 Property1 和 Property2 始终保证不为空,并且 属性 3,4 或 5 不为空。非空属性传递给这个新的 class:

public class EventResult
{
    public ulong Property1 {get; set;}
    public int Property2 {get; set;}
    public Object EventType {get; set;}
}

现在我有了一个漂亮整洁的 class,只有有效的属性。

这是我正在努力改进的地方。我想摆脱循环部分并将事件通知反序列化为正确的对应 class,只有有效属性。

public class Event1
{
    public ulong Property1 {get; set;}
    public int Property2 {get; set;}
    public class1 Event {get; set;}
}

public class Event2
{
    public ulong Property1 {get; set;}
    public int Property2 {get; set;}
    public class2 Event {get; set;}
}

public class Event3
{
    public ulong Property1 {get; set;}
    public int Property2 {get; set;}
    public class3 Event {get; set;}
}

我在想我可以使用 EventResult class 来反序列化事件通知;但是,我认为这行不通,因为 XMLElement 属性对于 class1、class2 和 class3 是不同的。

非常感谢有关此主题的任何帮助或讨论。

提前致谢。

您可以通过使用多个 [XmlElement(String, Type)] 属性,一个代表 object 的每个可能的子 class 可能作为 属性 值遇到的子class,给出每个要使用的元素名称:

[XmlRoot("event")]
public class EventResult
{
    [XmlElement("property1")]
    public ulong Property1 { get; set; }
    [XmlElement("property2")]
    public int Property2 { get; set; }

    [XmlElement("class1", typeof(class1))]
    [XmlElement("class2", typeof(class2))]
    [XmlElement("class3", typeof(class3))]
    public Object EventType { get; set; }
}

然后所有三个示例 XML 文件都可以一步反序列化。

为了安全起见,我会推荐

  1. 使所有 EventType class 继承自某些基础 class 或接口,或
  2. EventType 的 setter 中,确保传入的 value 是已知类型之一。如果不是,抛出一个 ArgumentException.

使 classes 继承事件 class

    [XmlInclude(typeof(class1))]
    [XmlInclude(typeof(class2))]
    [XmlInclude(typeof(class3))]
    [Serializable]
    [XmlRoot(ElementName = "event")]
    public class Event
    {
        [XmlElement("property1")]
        public ulong Property1 {get; set;}
        [XmlElement("property2")]
        public int Property2 { get; set; }
    }

    [Serializable]
    [XmlRoot(ElementName = "class1")]
    public class class1 : Event 
    {
        [XmlElement("property31")]
        public string Property31 { get; set; }
        [XmlElement("property32")]
        public string Property32 { get; set; }
        [XmlElement("property33")]
        public string Property33 { get; set; }
    }

    [Serializable]
    [XmlRoot(ElementName = "class2")]
    public class class2 : Event 
    {
        [XmlElement("property41")]
        public string Property41 { get; set; }
        [XmlElement("property42")]
        public int Property42 { get; set; }
    }

    [Serializable]
    [XmlRoot(ElementName = "class3")]
    public class class3 : Event
    {
        [XmlElement("property51")]
        public int Property51 { get; set; }
        [XmlElement("property52")]
        public string Property52 { get; set; }
        [XmlElement("property53")]
        public double Property53 { get; set; }
        [XmlElement("property54")]
        public string Property54 { get; set; }
    }​