2013-06-25 11 views
6

Tworzę program, który pozwala zdefiniować formuły użytkownika z 4 podstawowych operacji: dodawanie, odejmowanie, dzielenie, wiele przy użyciu XML. Weźmy przykład: Użytkownik chce zdefiniować formułę, taką jak (a + b) x (c + d). Format XML w następujący sposób:Deserializować xml do super klasy obiekt z C#

EDIT miałem wdrożyć to

EDIT rozwiązać. Wielkie dzięki za sugestię Yaniv. Moje rozwiązanie następująco:

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

klas

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

mam tylko do dekoracji Calculator nieruchomości z:

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

Odpowiedz

6

Domyślam chcesz używać XmlSerializer. Jeśli potrzebujesz "polimorficznej" deserializacji, możesz przekazać listę typów, o których powinien wiedzieć serser (działa to, jeśli wszystkie dziedziczą z tej samej klasy bazowej, ale nie z interfejsu).

Przykład:

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

Jest to wyjaśnione tutaj: Serializing and restoring an unknown class

Ale jest inny problem, że w XML Twój operand może posiadać dwa różne typy: operacja albo parametr (a, b, c, d) i nie możesz go reprezentować w klasie.

Coś, co zwykle jest to zobaczyć (I wdrożone jedynie operację dodawania, a ja jestem przy założeniu, że wyrażenie jest numeryczny):

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

ten sposób masz tylko jedną klasę bazową, więc wszystko jest prostsze. Jeśli to ma sens, domyślam się, że nietrafne będzie deserializowanie go.

EDIT: Jeśli klasa bazowa jest Kalkulator (zamiast wyrażenie) XML będzie wyglądać następująco:

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

Stworzyłem prosty kalkulator obiekt i szeregowane go i to, co mam. Jeśli będziesz deserializować to dostaniesz kalkulator, który zwróci 12.

Może możesz użyć XmlAttributes, aby zmienić nazwy elementów w XML lub, w najgorszym przypadku, napisać własny deserializer.

+0

Twoje wdrożenie naprawdę uratowało mój dzień. Ale jest coś, co nadal mylę, więc naprawdę doceniłbym, gdybyś poświęcił trochę swojego cennego czasu na wyjaśnienie. Po pierwsze: jakie jest znaczenie paremetera 'name' w konstrukcji" Paremeter "? Jak to jest, kiedy deserializuję mój XML? (nazwa operacji, jak "dodaj" | "odejmij" | "wiele" | "dziel") Po drugie: Czy muszę również przekazać typ klasy "Parametr" do "XmlSerializer"? Jeszcze raz dziękuję za odpowiedź i życzę miłego dnia, Sir! –

+0

Klasa parametrów (może ta nazwa nie jest dobra) dotyczy prostych argumentów operacji (np. A, b, c, d).Nie jestem pewien, w jaki sposób zamierzasz go użyć. Skąd bierzesz wartości operandów (a = 10)? Powinieneś dodać klasę parametrów do extraTypes. Zmienię moją odpowiedź, aby to odzwierciedlić. – Yaniv

+0

Dzięki za sugestię, spróbuję i będę otrzymywać informacje zwrotne JAK NAJSZYBCIEJ. Miłego dnia, proszę pana! –

Powiązane problemy