2

假设您有两个类,一个继承另一个,并且子需要使用 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 反序列化/序列化,然后将值复制回适当的位置。

有谁知道解决这个问题的更好方法?我可以让 XmlSerializer 以任何方式忘记父字典吗?

4

2 回答 2

4

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

现在,回到问题...

XmlSerializer查看声明类以获取输入;对于属性和条件序列化,不:此时我们不能将它们添加到类型模型中。但还有另一种选择——你可以XmlAttributeOverrides用来假装[XmlIgnore]字典上有一个成员。但是,一些重要的警告:

  • API使用XmlAttributeOverrides起来有点麻烦(参见 MSDN 示例)
  • 关键是您只执行一次,然后存储和重新使用XmlSerializer您以这种方式创建的;基本上,如果你这样做,它会在你每次new序列化程序时创建一个新的动态程序集,并且程序集永远不会卸载,所以你会出血;请注意,简单用法(new XmlSerializer(someType)等)为此具有内置缓存;但XmlAttributeOverrides用法

但同样,所有这些搞砸XmlAttributeOverrides的工作不仅仅是创建一个基本的 DTO

使用示例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字段如何用于缓存序列化程序。

于 2013-09-03T09:13:00.800 回答
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();
    }
}
于 2013-09-03T09:12:59.677 回答