如何在C#中从xml序列化包含多种数据类型的列表?

cha*_*nan 5 .net c# serialization

我想将以下XML反序列化/序列化为对象.

    <Discounts>
      <Discount Type="Voucher" Key="ABCD00001" Percent="2" />
      <Discount Type="Quantity">
        <Periods>
          <Period From="Thu, 31 Dec 2009 23:00:00 GMT" Quantity="1" />
          <Period From="Thu, 31 Dec 2009 23:00:00 GMT" Quantity="2" />
        </Periods>
      </Discount>
    </Discounts>
Run Code Online (Sandbox Code Playgroud)

是否可以让@Type属性定义应该使用哪种类型的对象进行序列化?

例如,在C#中:

[XmlArray]
[XmlArrayItem("Discount",typeof(Voucher)]
[XmlArrayItem("Discount",typeof(Quantity)]
public List<Discount> Discounts { get; set; }
Run Code Online (Sandbox Code Playgroud)

我希望我的解释是有道理的.任何帮助,将不胜感激.谢谢.

Andrew Anderson回答后更新:

这是更新的XML:

    <Discounts>
      <Discount xsi:Type="Voucher" Key="ABCD00001" Percent="2" />
      <Discount xsi:Type="Quantity">
        <Periods>
          <Period From="Thu, 31 Dec 2009 23:00:00 GMT" Quantity="1" />
          <Period From="Thu, 31 Dec 2009 23:00:00 GMT" Quantity="2" />
        </Periods>
      </Discount>
    </Discounts>
Run Code Online (Sandbox Code Playgroud)

我改变了我的类看起来像这样:

    [Serializable]
    [XmlInclude(typeof(Voucher))]
    [XmlInclude(typeof(Quantity))]
    [XmlRoot("Discount")]
     public class Discount
    { ... }

    public class Quantity : Discount { }

    public class Voucher : Discount { }
Run Code Online (Sandbox Code Playgroud)

当我反序列化时,'折扣'列表有两个'折扣'对象.我希望在这一点上列表应该有一个'Quantity'对象和'Voucher'对象.这可能是因为我的列表被定义为只有一个'Discount'对象.以下是我的'折扣'列表对象的代码.

    [XmlArray]
    [XmlArrayItem("Discount")]
    public List<Discount> Discounts { get; set; }
Run Code Online (Sandbox Code Playgroud)

现在的问题是如何设置列表以包含两种不同类型的对象?

And*_*son 5

如果您可以控制XML,则可以使用XmlIncludeDiscount基类上的属性来处理此问题.

例如(未经测试的代码):

[Serializable]
[XmlInclude(typeof(Voucher))]
[XmlInclude(typeof(Quantity))]
[XmlRoot("Discount")]
public class Discount {    }

public class Quantity : Discount { }
public class Voucher : Discount { }
Run Code Online (Sandbox Code Playgroud)

生成的Xml将如下所示:

<Discounts>
  <Discount xsi:type="Voucher" Key="ABCD00001" Percent="2" />
  <Discount xsi:type="Quantity">
    <Periods>
      <Period From="Thu, 31 Dec 2009 23:00:00 GMT" Quantity="1" />
      <Period From="Thu, 31 Dec 2009 23:00:00 GMT" Quantity="2" />
    </Periods>
  </Discount>
</Discounts>
Run Code Online (Sandbox Code Playgroud)

更新:

下面是一组示例类和一个控制台应用程序,用于演示此格式的序列化和解除序列.

首先是数据定义:

[Serializable]
public class Shopping
{
    [XmlArray]
    [XmlArrayItem("Discount")]
    public List<Discount> Discounts { get; set; }
}

[Serializable]
[XmlInclude(typeof(Voucher))]
[XmlInclude(typeof(Quantity))]
[XmlRoot("Discount")]
public class Discount
{
    public int Amount { get; set; }
}

public class Quantity : Discount
{
    public int MyQuantity { get; set; }
}

public class Voucher : Discount
{
    public string MyVoucherName { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

测试应用程序:

public class Program
{
    static void Main(string[] args)
    {
        XmlSerializer xs = new XmlSerializer(typeof(Shopping));

        var myShopping = new Shopping();
        myShopping.Discounts = new List<Discount>();
        myShopping.Discounts.Add(new Voucher() {MyVoucherName = "Foo", Amount = 6});
        myShopping.Discounts.Add(new Quantity() { MyQuantity = 100, Amount = 6 });

        StringBuilder xml = new StringBuilder();
        XmlWriter xmlWriter = XmlWriter.Create(xml);

        xs.Serialize(xmlWriter, myShopping);

        Console.WriteLine("Serialized:");
        Console.WriteLine(xml);

        Console.WriteLine();
        Console.WriteLine("Deserialized:");

        TextReader tr = new StringReader(xml.ToString());
        var myNewShopping = (Shopping) xs.Deserialize(tr);

        if (myNewShopping.Discounts != null)
        {
            foreach (var discount in myNewShopping.Discounts)
            {
                if (discount is Voucher)
                {
                    var voucher = (Voucher) discount;
                    Console.WriteLine("Voucher - Amount={0}, Name={1}", voucher.Amount, voucher.MyVoucherName);
                }
                else if (discount is Quantity)
                {
                    var quantity = (Quantity)discount;
                    Console.WriteLine("Quantity - Amount={0}, #={1}", quantity.Amount, quantity.MyQuantity);
                }
                else
                {
                    Console.WriteLine("Discount - Amount={0}", discount.Amount);
                }
            }
        }
        else
        {
            Console.WriteLine("No Discounts found");
        }

        Console.ReadKey();
    }
Run Code Online (Sandbox Code Playgroud)