2013-06-25 64 views
6

我正在创建一个程序,允许用户使用4种基本操作定义公式:使用XML添加,减去,除,多重。我们举个例子:用户想要定义像(a + b) x (c + d)这样的公式。该XML的如下格式:我有将xml反序列化为超类对象,并使用C#

编辑实现这个

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

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

我只是装饰Calculator属性搭配:

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

回答

6

我猜你想使用的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; 
    } 
} 

这样,你只有一个基类,所以一切都是简单。如果这是有道理的,我想它不会很难反序列化它。

编辑: 如果基类是计算器(而不是表达式)的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中元素的名称,或者在最糟糕的情况下编写自己的解串器。

+0

您的实施确实节省了我的一天。但是我仍然有些困惑,所以如果您花一些宝贵的时间来解释它,我会非常感激。 第一:'Paremeter'构造中'name'参数的含义是什么?当我反序列化XML时,会出现什么情况? (操作名称,如“add”|“subtract”|“multiple”|“divide”) 第二:我是否也必须将'Parameter'类的类型传递给'XmlSerializer'? 再一次,非常感谢您的回应,并祝您有愉快的一天,先生! –

+0

参数类(可能名称不太好)适用于简单操作数(例如a,b,c,d)。我不确定你将如何使用它。你从哪里得到操作数的值(a = 10)?您应该将参数类添加到extraTypes。我将编辑我的答案以反映它。 – Yaniv

+0

感谢您的建议,我会试一试,并尽快向您反馈。先生,祝你有美好的一天! –

相关问题