XmlSerializer - 忽略继承的不可序列化成员

时间:2013-09-03 09:00:19

标签: c# xmlserializer

假设您有两个类,一个继承另一个,并且需要使用XmlSerializer对子进行序列化/反序列化。但是,父级包含一个不可序列化的成员,比如字典。

public class Parent {

    public Dictionary<string, int> dictionary;
}

父类是用于许多其他脚本的库。它无法修改。现在,子类只包含可序列化的成员:

public class Child : Parent {

    [XmlElement]
    public int foo;

}

尝试调用序列化程序时,收到错误消息,指出字典不可序列化。在尝试使用JSON进行序列化时,我设法以警告的价格逃脱。我刚刚创建了另一个具有相同名称和类型的成员,并使用了ScriptIgnore:

public class Child : Parent {

    public int foo;

    [ScriptIgnore]
    public Dictionary<string, int> dictionary;

}

我在这里再次尝试了相同的技巧(通过使用XmlIgnore),但是效果不好,错误是一样的。我设法完成的唯一方法是创建单独的类,它们只提供xml de / serializing,然后将值复制回适当的位置。

有没有人知道更好的解决方法?我能否以任何方式让XmlSerializer忘记父词典?

2 个答案:

答案 0 :(得分:4)

我会说的第一件事,并且总是说:如果序列化现有模型变得棘手 - 甚至远程尴尬,那么 停止这样做 。花2分钟创建一个单独的DTO模型,即仅为了序列化而创建的模型(实际上,甚至可能针对特定的序列化器定制)。现在你输入了正确的类型,正确的成员,正确的属性和正确的布局。您需要做的就是添加一些转换方法 - 静态转换运算符在这里工作得很好。所以我要说的是:创建一个ParentDtoChildDto(你的名字可能会有所不同);它需要3分钟,而且效果很好。

现在,回到问题......

XmlSerializer查看声明类的输入;对于属性和条件序列化,没有:此时我们无法将这些添加到类型模型中。但还有另一种选择 - 您可以使用XmlAttributeOverrides假装词典成员上有[XmlIgnore]。但是,一些重要的警告:

  • XmlAttributeOverrides API有点使用(请参阅MSDN示例)
  • 严重 您只需执行一次,然后存储并重新使用您创建的XmlSerializer这条路;基本上,如果你这样做,每次new一个序列化程序,并且程序集永不卸载时,它将创建一个新的动态程序集,所以你将出血记忆;请注意,简单用法(new XmlSerializer(someType)等)具有内置缓存;但XmlAttributeOverrides用法

但是,与{em>创建基本DTO

相比,所有这些与XmlAttributeOverrides混乱的工作要多得多。

使用XmlAttributeOverrides

的示例
using System;
using System.Collections.Generic;
using System.Xml.Serialization;
public class Parent {
    public Dictionary<string, int> WantToIgnoreThis { get; set; }
}    
public class Child : Parent {
    public int Foo { get; set; }
}
static class Program
{
    static readonly XmlSerializer customSerializer;

    static Program()
    {
        var xao = new XmlAttributeOverrides();
        xao.Add(typeof(Parent), "WantToIgnoreThis", new XmlAttributes {
            XmlIgnore = true
        });
        customSerializer = new XmlSerializer(typeof(Child), xao);
    }
    static void Main()
    {
        //var ser = new XmlSerializer(typeof(Child));
        // ^^ this would fail

        customSerializer.Serialize(Console.Out, new Child {
            Foo = 123
        });
    }
}

特别注意static字段如何用于缓存序列化程序。

答案 1 :(得分:1)

您可以自己实施IXmlSerializable并处理ReadXml(XmlReader reader)WriteXml(XmlWriter writer)中的细节。如果您的类实现它们而不是生成自己的序列化器,XmlSerializer将调用这些方法。

public class Child : Parent, IXmlSerializable
{
    public int Foo { get; set; }
    public Dictionary<string, int> Dictionary { get; set; }

    public void WriteXml(XmlWriter writer)
    {
        writer.WriteStartElement("Foo");
        writer.WriteValue(this.Foo);
        writer.WriteEndElement();
    }

    void ReadXml(XmlReader reader)
    {            
        var wasEmpty = reader.IsEmptyElement;
        reader.Read();

        if (wasEmpty)
        {
            return;
        }

        reader.ReadStartElement("Foo");
        this.Foo = reader.ReadContentAsInt();
        reader.ReadEndElement();
    }
}