我正在创建一个程序,允许用户使用基本操作定义公式:使用
XML进行加,减,除,多.让我们举一个例子:用户想要定义像(a b)x(c d)这样的公式. xml的格式如下:
编辑我实现了这一点
- <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>
类
- //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(Subtract))]
- [XmlElement("Divide",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();
- }
- }
- [XmlElement("Multiple",typeof(Multiple))]
- [XmlElement("Add",typeof(Add))]
- [XmlElement("Subtract",typeof(Divide))]
- [XmlElement("Divide",typeof(Divide))]
- [XmlElement("Operator",typeof(Operand))]
解决方法
我猜你想要使用XmlSerializer.
如果需要“多态”反序列化,则可以传递序列化程序应该知道的类型列表(如果它们都从相同的基类继承而不是从接口继承,则可以使用).
如果需要“多态”反序列化,则可以传递序列化程序应该知道的类型列表(如果它们都从相同的基类继承而不是从接口继承,则可以使用).
例:
- 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());
它在这里解释:
Serializing and restoring an unknown class
但是还有一个问题,在你的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;
- }
- }
这样你只有一个基类,所以一切都更简单.如果这有意义,我想将其反序列化并不困难.
编辑:
如果基类是Calculator(而不是Expression),则XML将如下所示:
- <Calculator xsi:type="Multiple">
- <calculators>
- <Calculator xsi:type="Add">
- <calculators>
- <Calculator xsi:type="Operator">
- <value>12</value>
- </Calculator>
- </calculators>
- </Calculator>
- </calculators>
- </Calculator>
我创建了一个简单的计算器对象并将其序列化,这就是我所得到的.如果您将反序列化它,您将获得一个将返回12的计算器.
也许您可以使用XmlAttributes来更改XML中元素的名称,或者在最坏的情况下编写自己的反序列化器.