2013-06-25 9 views
6

私は、基本的な4つの操作でユーザ定義の数式を追加する、減算する、除算する、複数のXMLを使用するプログラムを作成しています。例を挙げてみましょう:ユーザーは(a + b) x (c + d)のような公式を定義します。次のようなXMLのフォーマット:C#でスーパークラスオブジェクトにxmlをデシリアライズ

EDIT私はこの

EDIT解決を実装しました。 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プロパティを飾るために持っている:私はあなたがXmlSerializerをを使用したい推測してい

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

答えて

6

。 "多型"の直列化が必要な場合は、シリアライザが知っておくべき型のリストを渡すことができます(すべてが同じ基本クラスから継承され、インタフェースから継承されない場合は機能します)。

例:ここで説明しています

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であなたのオペランドが二つの異なるタイプを保持できるという別の問題がある:操作やパラメータ(、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; 
    } 
} 

すべてが簡単ですので、あなたが唯一の基本クラスを持ってこの方法:私は通常見

何かが、これは(私が唯一の追加操作を実現し、私は表現が数値であると仮定しています)です。それが意味をなさなければ、私はそれを逆直列化することは難しくないと思う。

EDIT:基底クラスは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'建設の '名前' paremeterの意味は何ですか? XMLをデシリアライズすると、どうなるでしょうか? ( "add" | "subtract" | "multiple" | "divide"のような操作の名前) 2番目: 'Parameter'クラスの型を' XmlSerializer'にも渡す必要がありますか? もう一度、お返事いただきありがとうございました。素敵な日です。 –

+0

パラメータクラス(名前が多分そうでないかもしれません)は、単純なオペランド(a、b、c、dなど)のものです。どのようにあなたがそれを使用しようとしているのか分かりません。オペランド(a = 10)の値はどこで得られますか? extraTypesにパラメータクラスを追加する必要があります。私はそれを反映するために私の答えを編集します。 – Yaniv

+0

あなたの提案をお寄せいただきありがとうございます。私は試していただき、できるだけ早くご返信させていただきます。良い一日を! –

関連する問題