【问题标题】:XmlSerializer - Ignoring inherited unserializable memberXmlSerializer - 忽略继承的不可序列化成员
【发布时间】:2013-09-06 10:33:51
【问题描述】:

假设您有两个类,一个继承另一个,并且子需要使用 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 以任何方式忘记父字典吗?

【问题讨论】:

    标签: c# xmlserializer


    【解决方案1】:

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

    现在,回到问题...

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

    • XmlAttributeOverrides API 使用起来有点麻烦(有关示例,请参见 MSDN)
    • 关键您只执行此操作一次,然后存储并重复使用您以这种方式创建的 XmlSerializer ;基本上,如果您这样做,它会在您每次new 序列化程序时创建一个新的动态程序集,并且程序集永远不会卸载,因此您会大量使用内存;请注意,simple 用法(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 字段是如何用于缓存序列化程序的。

    【讨论】:

      【解决方案2】:

      您可以自己实现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();
          }
      }
      

      【讨论】:

      • IXmlSerializable API(尤其是读取)非常难以处理琐碎案例之外的任何事情;所以对于任何复杂的东西,它要么变成大量的代码痛苦,要么你最终拥有 DOM API 的开销(XmlDocumentXDocument),只是为了避免手工编写复杂的读取方法的痛苦。为了我的钱,我说这是一个花费大量时间查看序列化的人:实现IXmlSerializable 根本不值得痛苦。当然是 YMMV。
      猜你喜欢
      • 1970-01-01
      • 2010-12-06
      • 1970-01-01
      • 1970-01-01
      • 2020-01-31
      • 2013-06-25
      • 1970-01-01
      • 1970-01-01
      • 2014-02-01
      相关资源
      最近更新 更多