【问题标题】:Ignoring properties on derived classes when using .NET's XmlSerializer使用 .NET 的 XmlSerializer 时忽略派生类的属性
【发布时间】:2011-07-13 14:15:41
【问题描述】:

我有一个带有虚拟属性的基类和一个覆盖虚拟属性的派生类型。该类型可以序列化为 XML。当对象是派生类型时,我要做的不是保留项目列表属性。为了实现这一点,派生类使用[XmlIgnore] 属性装饰被覆盖的属性。基类中的虚拟属性不应用 XmlIgnore 属性。由于某种原因,即使对象是派生类型 (DynamicCart),项目列表也会被序列化。

当我将XmlIgnore 属性应用于基类中的虚拟属性时,列表不会序列化到文件中。

public class ShoppingCart
{  
   public virtual List<items> Items{get; set;}

   //and other properties 

   public void SerializeToXML (string filePath)
   {
     var xmlSerializer = new XmlSerializer(this.GetType());
     textWriter = new System.IO.StreamWriter(filePath);
     xmlSerializer.Serialize(textWriter, this);
     textWriter.Flush();
     textWriter.Close();  
   }
}

//A cart that is populated by algo based on parameters supplied by user. I have no need to
//persist the actual items across sessions.
class DynamicCart: ShoppingCart
{
   [XmlIgnore]
   public override List<items>{get;set;}
   //and other properties 
}

class Shop
{
   ShoppingCart cart = new DynamicCart();
   PopulateCart(cart);
   cart.serializeToXML(<PATH TO FILE>);
}

【问题讨论】:

  • 看来你自己回答了这个问题。
  • 我已经实现了一个解决方法,但没有回答我的问题,为什么 XMLSerializer 在序列化 DynamicCart 时不遵守服务类中的 [XMLIgnore] 属性并包含 List 对象?

标签: .net inheritance virtual overriding xmlserializer


【解决方案1】:

我猜你需要在基类中声明派生类型才能进行 XML 序列化。听起来有点傻,但符合规范。

查看此MSDN page,并查找以下示例:

[System.Xml.Serialization.XmlInclude( typeof( Derived ) )]
public class Base
{
    // ...
}

【讨论】:

  • 在类中添加这个属性并没有解决问题。即使派生类中的重写属性具有 [XMLIgnore] 属性,序列化程序仍继续序列化 List。我终于结束了;从派生类中删除被覆盖的属性;如果正在序列化派生类,则在基类中编写条件序列化逻辑以应用 XMLIgnore 属性。
  • 关于为什么序列化程序不支持派生类中的 [XMLIgnore] 属性的任何线索??
【解决方案2】:

试试这个

  XmlSerializer serializer = new XmlSerializer(typeof(DynamicCart), new Type[]{typeof(ShoppingCart)});

这将允许您添加尽可能多的类型,您希望序列化程序包含在内。

【讨论】:

    【解决方案3】:

    我认为您的序列化程序正在使用您的基类而不是派生类。

    public void SerializeToXML(string filePath, Type type)
    {
        xmlSerializer = new XmlSerializer(type);
        textWriter = new System.IO.StreamWriter(filePath);
        xmlSerializer.Serialize(textWriter, this);
        textWriter.Flush();
        textWriter.Close();
    }
    
    class Shop
    {
        ShoppingCart cart= new DynamicCart();
        PopulateCart(cart);
        cart.serializeToXML(<PATH TO FILE>, typeof(DynamicCart));
    }
    

    【讨论】:

      【解决方案4】:

      您可以通过向基类添加一个虚拟的ShouldSerialize*** 方法来做到这一点。例如:

      [XmlInclude(typeof(Sub))]
      public class Base
      {
          public virtual string Prop { get; set; }
      
          public virtual bool ShouldSerializeProp() { return true; }
      }
      
      public class Sub : Base
      {
          public override string Prop { get; set; }
      
          public override bool ShouldSerializeProp() { return false; }
      }
      
      internal class Program
      {
          private static void Main()
          {
              var o = new Sub { Prop = "Value" };
      
              var baseSer = new XmlSerializer(typeof (Base));
              var subSer = new XmlSerializer(typeof (Sub));
      
              Console.Out.WriteLine("BASE:");
              baseSer.Serialize(Console.Out, o);
              Console.Out.WriteLine();
      
              Console.Out.WriteLine("SUB:");
              subSer.Serialize(Console.Out, o);
              Console.Out.WriteLine();
      
              Console.ReadLine();
          }
      }
      

      这会产生(稍微整理一下):

      BASE:
      <Base xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Sub">
        <Prop>Value</Prop>
      </Base>
      
      SUB:
      <Sub />
      

      该方法必须在ShouldInclude... 之后包含要考虑的属性的确切名称。

      【讨论】:

        【解决方案5】:

        如果我理解得很好,您正在尝试做的是对基类的有损转换,也称为slicing(至少在 C++ 中)。

        如果您有能力将您的类转换为records(我相信就是这种情况),那么代码非常简单,因为您可以使用基类的合成复制构造函数。

        public record ShoppingCart
        {
            public virtual List<item> Items
            {
                get;
                set;
            }
        
            //and other properties 
            public void SerializeToXML(string filePath)
            {
                var xmlSerializer = new XmlSerializer(typeof(ShoppingCart)); // type needs to be fixed here
                textWriter = new System.IO.StreamWriter(filePath);
                xmlSerializer.Serialize(textWriter, new ShoppingCart(this)); // synthesized copy constructor
                textWriter.Flush();
                textWriter.Close();  
            }
        }
        

        剩下的代码仍然存在。看看see it at work 的稍作修改的演示。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-10-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-07-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多