How to deserialize a concrete implementation of an abstract class from XML

I have an abstract class with several specific implementations. This is necessary for serialization in XML to be sent to another system - this works fine. However, I also need to be able to deserialize the same XML structure. No matter what I try, I seem to be unable to do this. My class structure is as follows:

Abstract class:

[XmlIncludeAttribute(typeof(ConcreteFooOne))] [XmlIncludeAttribute(typeof(ConcreteFooTwo))] [XmlIncludeAttribute(typeof(ConcreteFooThree))] [XmlRoot(ElementName = "FooData", Namespace="http://foo.bar")] public abstract partial class AbstractFoo { // Some abstract props etc. } 

Concrete class example:

 public partial class ConcreteFooOne : AbstractFoo { // Some properties, constructor etc. } 

XML root example:

 <FooData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ConcreteFooOne" RequestResponse="Request" xmlns="http://foo.bar"> 

An example is the XML root example, which seems to relate to the problem. Now I can serialize fine, but when deserializing, if I deserialize by going into an abstract type, I certainly get an exception stating that the type "AbstractFoo" is abstract. So I just changed the logic so that a concrete type (ConcreteFooOne in this case) is passed to the serializer instead. Now I get β€œhttp://foo.bar"> not expected. "I assume this is because the serializer does not know what the root node needs?

I have a node root defined in an abstract class, since it will be the same for all concrete concrete implementations. The specific type is determined by the "RequestResponse" attribute (or the xsi: type attribute may also work if present, as this gives us the actual type name). Is there a way to get the serializer to pick up what is required from an abstract class, or am I completely wrong about that?

  • Please note that I cannot change the structure of the class too much, as it is very closely related to some XML schemes provided by a third party.

Thanks in advance for helping with this, it would be very grateful.

+4
source share
2 answers

Add [XmlRoot (ElementName = "FooData", Namespace = " http://foo.bar ")] to subclasses

here is an example i made:

  [XmlIncludeAttribute(typeof(ConcreteFooOne))] [XmlIncludeAttribute(typeof(ConcreteFooTwo))] [XmlIncludeAttribute(typeof(ConcreteFooThree))] [XmlRoot(ElementName = "FooData", Namespace = "http://foo.bar")] public abstract partial class AbstractFoo { // Some abstract props etc. } [XmlRoot(ElementName = "FooData", Namespace = "http://foo.bar")] public class ConcreteFooOne : AbstractFoo { public int MyProp { get; set; } } [XmlRoot(ElementName = "FooData", Namespace = "http://foo.bar")] public class ConcreteFooTwo : AbstractFoo { } [XmlRoot(ElementName = "FooData", Namespace = "http://foo.bar")] public class ConcreteFooThree : AbstractFoo { } class Program { static void Main(string[] args) { var serializer = new System.Xml.Serialization.XmlSerializer(typeof(AbstractFoo)); using (var stream = new FileStream("test.txt", FileMode.OpenOrCreate)) { serializer.Serialize(stream, new ConcreteFooOne() { MyProp = 10 }); stream.Flush(); } using (var stream = new FileStream("test.txt", FileMode.OpenOrCreate)) { var c = serializer.Deserialize(stream); } } } 
+4
source

it's simple, in the client, when you deserealize, define the XmlSerializer as:

 XmlSerializer xs= new XmlSerializer (typeof (AbstractFoo), new Type[] { typeof (ConcreteFooOne), typeof (ConcreteFooTwo) } ); 

then you can try:

 //it instantiate the correct class, need a streamreader var myclass = xs.Deserialize(reader); if (myclass is ConcreteFooOne) //do something if (myclass is ConcreteFooTwo) //do something 
+1
source

Source: https://habr.com/ru/post/1492274/


All Articles