Deserialize xml to c # superclass object

I am creating a program that allows the user to define formulas with four basic operations: add, subtract, divide, reuse XML. Take an example: the user wants to define a formula, for example (a + b) x (c + d) . Xml format:

EDIT I implemented this

EDIT . Thanks a lot Yaniv . My decision:

 <xPlugins> <xPlugin> <Multiple> <Add> <Operator> <value>1</value> </Operator> <Operator> <value>2</value> </Operator> </Add> <Add> <Operator> <value>3</value> </Operator> <Operator> <value>4</value> </Operator> </Add> </Multiple> </xPlugin> </xPlugins> 

Classes

 //root element public class xPlugins { [XmlElement("xPlugin", typeof(xPlugin))] public xPlugin[] Plugin { get; set; } } public class xPlugin { [XmlElement("Multiple", typeof(Multiple))] [XmlElement("Add", typeof(Add))] [XmlElement("Subtract", typeof(Divide))] [XmlElement("Divide", typeof(Divide))] [XmlElement("Operator", typeof(Operand))] public Calculator calculator { get; set; } } //Deseirialize ultility static class readXML { public static void getObject(ref xPlugins plugins) { try { List<Type> type = new List<Type>(); type.Add(typeof(Add)); type.Add(typeof(Minus)); type.Add(typeof(Multiple)); type.Add(typeof(Subtract)); type.Add(typeof(Operator)); XmlSerializer xml = new XmlSerializer(typeof(xPlugin), type.ToArray()); FileStream fs = new FileStream("test.xml", FileMode.Open); plugins = (xPlugins)xml.Deserialize(fs); } catch (Exception ex) { throw; } } } public abstract class Calculator { [XmlElement("Multiple", typeof(Multiple))] [XmlElement("Add", typeof(Add))] [XmlElement("Subtract", typeof(Subtract))] [XmlElement("Divide", typeof(Divide))] [XmlElement("Operator", typeof(Operand))] public List<Calculator> calculators{ get; set; } public virtual int Calculate() { return 0; } } public class Operator : Calculator { public int value { get; set; } public Operator() { } public override int Calculate() { return value; } } public class Add : Calculator { public Add() { } public override int Calculate() { List<int> value = new List<int>(); foreach (Calculator calculator in calculators) { value.Add(calculator.Calculate()); } return value.Sum(); } } public class Minus : Calculator { public Minus() { } public override int Calculate() { int value = calculators[0].Calculate(); for (int i = 1; i < calculators.Count; i++) { value -= calculators[i].Calculate(); } return value; } } public class Divide: Calculator { public Divide() { } public override int Calculate() { int value = calculators[0].Calculate(); for (int i = 1; i < calculators.Count; i++) { value /= calculators[i].Calculate(); } return value; } } public class Multiple : Calculator { public Multiple() { } public override int Calculate() { int value = calculators[0].Calculate(); for (int i = 1; i < calculators.Count; i++) { value *= calculators[i].Calculate(); } return value; } } //running test private void button1_Click(object sender, EventArgs e) { readXML.getObject(ref this.plugins); foreach (Calculator plugin in plugins.calculators) { plugin.Calculate(); } } 

I just need to decorate the Calculator property:

 [XmlElement("Multiple", typeof(Multiple))] [XmlElement("Add", typeof(Add))] [XmlElement("Subtract", typeof(Divide))] [XmlElement("Divide", typeof(Divide))] [XmlElement("Operator", typeof(Operand))] 
+6
source share
1 answer

I assume you want to use the XmlSerializer. If you need "polymorphic" deserialization, you can pass a list of types that the serializer should know about (this works if they all inherit from the same base class, but not from the interface).

Example:

 List<Type> extraTypes = new List<Type>(); extraTypes.Add(typeof(multiple)); extraTypes.Add(typeof(add)); extraTypes.Add(typeof(substract)); extraTypes.Add(typeof(divide)); var ser = new XmlSerializer(typeof(Foo), extraTypes.ToArray()); 

It explains: Serializing and restoring an unknown class

But there is another problem: in your XML, your operand can contain two different types: an operation or a parameter (a, b, c, d), and you cannot represent it in your class.

Something that I usually see is (I implemented only the add operation, and I assume that the expression is numeric):

 public class Expression { public virtual int Evaluate() { } } public class Add : Expression { Expression _left; Expression _right; public Add(Expression left, Expression right) { _left = left; _right = right; } override int Evalute() { return _left.Evalute() + _right.Evalute(); } } public class Parameter : Expression { public int Value{get;set;} public Parameter(string name) { // Use the name however you need. } override int Evalute() { return Value; } } 

Thus, you have only one base class, so everything is simpler. If that makes sense, I think it would be impractical to deserialize it.

EDIT: If the base class is a calculator (instead of an expression), the XML will look like this:

 <Calculator xsi:type="Multiple"> <calculators> <Calculator xsi:type="Add"> <calculators> <Calculator xsi:type="Operator"> <value>12</value> </Calculator> </calculators> </Calculator> </calculators> </Calculator> 

I created a simple calculator object and serialized it and what I got. If you do deserialization, you get a calculator that will return 12.

Perhaps you can use XmlAttributes to change element names in XML, or in the worst case write your own deserializer.

+6
source

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


All Articles