2010-06-14 73 views
5

我想将以下XML反序列化/序列化为一个对象。如何用xml中的C#中的多个数据类型序列化列表?

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

是否有可能让@Type属性定义应使用哪种类型的对象来序列化?

例如,在C#:

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

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

后更新安德鲁·安德森答案:

以下是更新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> 

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

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

    public class Quantity : Discount { } 

    public class Voucher : Discount { } 

当我反序列化这个,“折扣”列表有两个“折扣”对象。我期望在这一点上,清单应该有一个'数量'对象和'凭证'对象。这可能是因为我的列表被定义为只有一个“折扣”对象。以下是我的“折扣”列表对象的代码。

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

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

+0

另外,你对XML的外观灵活,或者它必须是完全按照您所贴? – 2010-06-14 15:55:48

+0

你负责格式吗?如果是这样,为什么不用XML中的“VoucherDiscount”和“QuantityDiscount”替换“Discount”? – Joseph 2010-06-14 15:59:32

+0

当它出现时,对它使用样式表似乎是最容易的,当它出来时,但我想避免改变任何东西。 – chafnan 2010-06-14 16:51:37

回答

5

如果您可以控制XML,则可以使用Discount基类中的XmlInclude属性来处理此问题。

例如(超前未测试的代码):

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

public class Quantity : Discount { } 
public class Voucher : Discount { } 

生成的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> 

UPDATE

这里是类的样本集与一个控制台应用程序来演示从这种格式的序列化& deserialing。

首先,数据定义:

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

与测试程序:

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

我在我的样本中有一堂课。在您的帖子中,您可以装饰折扣列表 - 除[XmlArray]之外,您不需要任何其他属性。 – 2010-06-14 17:00:23

+0

工作。现在的问题是,现在列表中的类型对象是“折扣”,因为我希望它是加载的对象的类型,例如“数量”或“凭证”。无论如何让加载的对象在列表中是正确的? – chafnan 2010-06-14 17:02:25

+0

对不起,我删除了我的第一条评论,因为我读了你的回答错误,并在错误的地方应用了XmlInclude。 – chafnan 2010-06-14 17:03:11