开发者

How to serialize a derived class as its base class

I have a derived class that adds only methods to a base class. How can one serialize the derived class so that it matches the serialization of the base class? i.e. The serialized xml of the derived class should 开发者_开发知识库look like:

<BaseClass>
  ...
</BaseClass>

e.g. The following will throw an InvalidOperationException

The type DerivedClass was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically.

Class BaseClass {}

Class DerivedClass : BaseClass {}

DerivedClass derived = new DerivedClass();

StreamWriter stream = new StreamWriter("output file path");
XmlSerializer serializer = new XmlSerializer(GetType(BaseClass));
serializer(stream, derived);


You'll have to pass GetType(DerivedClass) to the serializer constructor, it must match the type of the object you serialize. You can use the <XmlRoot> attribute to rename to the root element. This example code worked as intended:

using System;
using System.Xml.Serialization;
using System.IO;

class Program {
  static void Main(string[] args) {
    var obj = new DerivedClass();
    obj.Prop = 42;
    var xs = new XmlSerializer(typeof(DerivedClass));
    var sw = new StringWriter();
    xs.Serialize(sw, obj);
    Console.WriteLine(sw.ToString());

    var sr = new StringReader(sw.ToString());
    var obj2 = (BaseClass)xs.Deserialize(sr);
    Console.ReadLine();
  }
}

public class BaseClass {
  public int Prop { get; set; }
}
[XmlRoot("BaseClass")]
public class DerivedClass : BaseClass { }


You can also implement ICloneable interface for BaseClass and then do :

var sw = new StringWriter()

var base = (derived as BaseClass).Clone()
var serializer = new XmlSerializer(typeof(BaseClass))
serializer.Serialize(sw, base)

Console.WriteLine(sw.ToString())

Not a perfect approche, but if your base class is simple then it should also work.


I haven't tried it but can you not just cast it ?

serializer(stream, (BaseClass)derived);

Edit

Also, if you want to have a single XmlSerialiser that can cope with multiple derived classes & the base class then you need to specify all of the types in the XmlSerialiser constructor.

  XmlSerializer serializer = new XmlSerializer(typeof(BaseClass), new Type[] {typeof(DerivedClass)});

Then it will happily serialize multiple types. However you will also have to use the solution mentioned above to get the output xml to match between classes.


After a little bit of googling ;) I can say that you'll need some more code and implement IXmlSerializable for your base class, declaring all interface methods as virtual and overriding them on your derived class. Here's a sample topic and similar problem resolved by interface mentioned.


The answer provided required making changes to the originating base class to deliver the proper name. I felt that was uneeded and will demonstrate a way to get the result on any class provided without changes to source.


By providing an extension method on a generic type one can provide this solution to any type as needed.

public static class SerializerExtensions
{
    public static string ToBaseNamedXml<T>(this T instance)
    {    
        var root = instance.GetType().BaseType.UnderlyingSystemType.Name; // Get base name.

        var jsr = JsonConvert.SerializeObject( instance );               // Into JSON

        var xDoc = JsonConvert.DeserializeXmlNode(jsr, root);            // Provide base name

        return xDoc.OuterXml;                                            // Out to string
    }
}

The above code uses Newtonsoft JSON serializer's nuget package to serialize into JSON which gets all the properties of the derived, but not the name of the derived like this {"dProp":90125,"Prop":42}. Then we reverse the process in JSON again but provide the root name from the derived object. Finally we return the XDocuments outer xml as a string.

Result <BaseClass><dProp>90125</dProp><Prop>42</Prop></BaseClass>


Test Classes Note I added to the test derived class a new property called dProp

public class BaseClass { public int Prop { get; set; } }

public class DerivedClass : BaseClass { public int dProp { get; set; } }

Test Usage

var dc = new DerivedClass() { Prop = 42, dProp = 90125} ;

var xmlStringResult = dc.ToBaseNamedXml();
0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜