开发者

Ignoring properties on derived classes when using .NET's XmlSerializer

I have a base class with a virtual property and a derived type that overrides the virtual property. The type can be serial开发者_如何学Pythonized to XML. What I am trying to do is NOT to persist the List of items property when the object is of the derived type. To acheive this the derived class decorates the overridden property with the [XmlIgnore] attribute. The virtual property in the base class does NOT apply XmlIgnore attribute. For some reason the List of items get serialized every even when the object is of the derived type (DynamicCart).

When I apply XmlIgnore attribute to the virtual property in the base class the list does not get serialized to file.

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>);
}


You can do this by adding a virtual ShouldSerialize*** method to the base class. For example:

[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();
    }
}

This produces (tidied slightly):

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

SUB:
<Sub />

The method must have include the exact name of the property to consider after ShouldInclude....


I think your serializer is using your base class instead of the derived.

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));
}


If I understand well, what you're trying to do is a lossy conversion to base class also called slicing (at least in C++).

If you can afford to turn your classes into records (which is the case, I believe), the code is pretty straightforward, as you can use the synthesized copy constructor of the base.

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();  
    }
}

The rest of the code remains. Take a look at a slightly modified demo to see it at work.


I guess you need to declare the derived type in the base class for XML serialization. Sounds a bit silly, but is by specification.

See this MSDN page, and look for the following example:

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


Try this

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

this will allow you to add as many types, you want serializer to inclusde.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜