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 XDocument
s 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();
精彩评论