c# - 使用 C# 将 xml 反序列化为父类(super class)对象

标签 c# xml-deserialization

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

编辑我已经实现了这个

编辑 解决。非常感谢 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))]

最佳答案

我猜您想使用 XmlSerializer。 如果您需要“多态”反序列化,您可以传递序列化程序应该知道的类型列表(如果它们都继承自相同的基类而不是接口(interface),则此方法有效)。

例子:

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 中元素的名称,或者在最坏的情况下编写您自己的反序列化程序。

关于c# - 使用 C# 将 xml 反序列化为父类(super class)对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17292634/

相关文章:

c# - 为什么我的 PHP SHA256 哈希不等同于 C# SHA256Managed 哈希

c# - 有没有办法用.Net 3.5在WPF中模拟UseLayoutRounding

c# - 如何将具有不同名称但具有相同属性集的 xml 元素反序列化为类型化数组/集合

c# - 如何仅将大型 xml 文件的一部分反序列化为 C# 类?

c# - XML 文档 (30, 14) FormatException : Input string was not in a correct format. 中存在错误?

C# Xml 反序列化,忽略 XML 中的数据

c# - 将 int 转换为字符串与 C# 中的 ToString() 方法有什么区别

c# - System.Threading.Tasks.Task 在循环中执行奇怪的行为

c# - 无法建立 SSL 连接。身份验证失败

c# - XML 反序列化 "Element was not expected"错误