使用C#将xml反序列化为超类对象

我正在创建一个程序,允许用户使用4个基本操作定义公式:使用XML进行加,减,除,多。 让我们举一个例子:用户想要定义像(a + b) x (c + d)这样的公式。 xml的格式如下:

编辑我实现了这一点

编辑解决。 非常感谢Yaniv的建议。 我的解决方案如下:

      1   2     3   4      

 //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 = new List(); 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 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 value = new List(); 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(); } } 

我只需用以下内容装饰Calculator属性:

 [XmlElement("Multiple", typeof(Multiple))] [XmlElement("Add", typeof(Add))] [XmlElement("Subtract", typeof(Divide))] [XmlElement("Divide", typeof(Divide))] [XmlElement("Operator", typeof(Operand))] 

我猜你想要使用XmlSerializer。 如果需要“多态”反序列化,则可以传递序列化程序应该知道的类型列表(如果它们都从相同的基类inheritance而不是从接口inheritance,则可以使用)。

例:

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

这里解释了: 序列化和恢复未知类

但是还有另一个问题,在XML中你的操作数可以包含两种不同的类型:操作或参数(a,b,c,d),你不能在你的类中表示它。

我经常看到的是这个(我只实现了添加操作,我假设表达式是数字):

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

这样你只有一个基类,所以一切都更简单。 如果这有意义,我想它反序列化并不困难。

编辑:如果基类是计算器(而不是表达式),XML将如下所示:

      12      

我创建了一个简单的计算器对象并将其序列化,这就是我得到的。 如果你将它反序列化,你会得到一个返回12的计算器。

也许你可以使用XmlAttributes来改变XML中元素的名称,或者在最坏的情况下编写你自己的反序列化器。