.NET XmlSerializer:基于属性值的多态映射

时间:2012-08-02 09:26:21

标签: .net mapping polymorphism xmlserializer

是否有本地方式映射以下xml ...

<Tag type="1" />
<Tag type="2" />

...具体类“Type1Tag”和“Type2Tag”(都来自抽象类Tag),基于“type”属性的值?

(类似于NHibernate的鉴别器:DiscriminateSubClassesOnColumn(...)/ DiscriminatorValue(...))

我不是在寻找XmlSerializer + Polymorphism中报告的映射,它通过标记名称来区分类型,而不是通过属性值(我不能更改xml结构)来区分:)

1 个答案:

答案 0 :(得分:3)

我在你的实施中可能为时已晚,无法提供任何帮助,但这是我周末想到的事情,并认为我会分享给其他人,因为它似乎满足了我的需求。

请注意,此处没有错误处理,您可以根据需要创建自己的子对象类型初始化。

我有许多不同的类,它们都是相同类型的元素,但可以根据属性的值保存不同的内容。

我使用IXmlSerializable - 接口并实现了方法来读取每个类型标记...

Xml输入:

<Parent>
  <Tag type="1"/>
  <Tag type="2"/>
</Parent>

父类实现IXmlSerializable

public class Parent : IXmlSerializable
{
    [XmlElement("Tag")]
    public List<TagBase> Tags { get; set; }

    #region IXmlSerializable Members

    public System.Xml.Schema.XmlSchema GetSchema()
    {
        return null;
    }

    public void ReadXml(System.Xml.XmlReader reader)
    {
       // this line causes the root Parent node to be ignored, and gets to the children Tag elements
       reader.Read();

       while (reader.ReadToNextSibling("Tag"))
       {
           string attributeType = reader.GetAttribute("type");

           Type type = null;

           switch(attributeType)
           {
              case "1":
                  type = typeof(Type1Tag);
                  break;
              case "2":
                  type = typeof(Type2Tag);
                  break;
              default:
                  continue;
           }

           XmlSerializer serializer = new XmlSerializer(type);

           // this line is the key to rejoining the automatic xml deserialization of all
           // the child stuff
           TagBase tagBase = (TagBase)serializer.Deserialize(reader.ReadSubtree());

           this.Tags.Add(tagBase);
        }
    }

    public void WriteXml(System.Xml.XmlWriter writer)
    {
        throw new NotImplementedException();
    }

    #endregion IXmlSerializable Members
}

我创建了一个抽象的TagBase - 类,每个标记类型都会继承:

[XmlRoot("Tag")]
public abstract class TagBase
{
   [XmlAttribute("type")]
   public string Type { get; set; }
}

然后,可以使用自定义属性等正常实现其他类...

[XmlRoot("Tag")]
public class Type1Tag : TagBase
{
    // your implementation
}

[XmlRoot("Tag")]
public class Type2Tag : TagBase
{
    // your implementation
}

注意,我在这里使用XmlRootAttribute并包含它们,因为我有一堆命名空间在尝试反序列化子标记时导致异常,但是YMMV。我还没有达到添加WriteXml - 方法的意义,但在这里应该非常简单......