如何将XML文档反序列化为List<>同时覆盖项目名称

时间:2011-07-13 20:12:58

标签: c# xml-serialization

我正在尝试将XML文档反序列化为List<>。我的目标是拥有List<>有一个公共静态方法,它返回从XML文档中填充的内容。

这是XML:

<?xml version="1.0"?>
<root>
    <item>
        <name>Blue</name>
    </item>
    <item>
        <name>Red</name>
    </item>
</root>

这是项目的类(BillingItem.cs):

using System;
using System.Xml.Serialization;

namespace DeserializeExample
{
    [Serializable]
    [XmlRoot("item")]
    public class BillingItem
    {
        [XmlElement("name")]
        public string Description { get; set; }
    }
}

这是列表(BillingItems.cs)的类:

using System;
using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;

namespace DeserializeExample
{
    [Serializable]
    [XmlRoot("root")]
    public class BillingItems : List<BillingItem>
    {
        public static BillingItems GetBillingItems()
        {
            using (TextReader reader = new StreamReader("BillingItems.xml"))
            {
                XmlSerializer serializer = new XmlSerializer(typeof(BillingItems));
                return (BillingItems)serializer.Deserialize(reader);
            }
        }
    }
}

以下是控制台应用程序,其中包含了我希望如何获取列表的示例(Program.cs):

namespace DeserializeExample
{
    class Program
    {
        static void Main(string[] args)
        {
            BillingItems billingItems = BillingItems.GetBillingItems();
        }
    }
}

控制台应用程序运行时,列表为空。我认为这与我如何使用属性有关,但我无法确定如何使用它。

我希望这个例子很简单,解释得很好,有人可以提供帮助。

3 个答案:

答案 0 :(得分:3)

我将封装列表 - 部分是为了简单(避免一些gnarly重载XmlSerializer构造函数),部分原因是因为CF等上有一些故障导致它不可靠的。但是:

public class BillingItem
{
    [XmlElement("name")]
    public string Description { get; set; }
}
[XmlRoot("root")]
public class MyResult
{
    [XmlElement("item")]
    public List<BillingItem> Items { get; set; }
}

(我删除了所有不必要的其他属性)

然后你只需返回MyResult(显然更恰当地命名),它将根据你的例子进行序列化。

答案 1 :(得分:1)

从您的示例看起来可能没有必要进行序列化。如果不是,请考虑使用LINQ-to-XML进行解析:

using System.Xml.Linq;

public class BillingItems : List<BillingItem>
{
    // Constructor.
    private BillingItems(List<BillingItem> items) : base(items) { }

    public static BillingItems GetBillingItems()
    {
        var doc = XDocument.Load("BillingItems.xml");
        var items = (from i in doc.Element("root").Elements("item")
                        select new BillingItem { Description = i.Element("name").Value })
                    .ToList();
        return new BillingItems(items);
    }
}

您可能还想考虑使用IEnumerable&lt;&gt;而不是List&lt;&gt;除非您打算插入/移除物品。

编辑:修改上面的代码,以便BillingItems根据下面的OP评论继承List&lt;&gt ;.

答案 2 :(得分:0)

好吧,虽然我不喜欢这个,因为我相信XmlSerializer中有一些东西会为我做这件事,但是在此期间我会做以下事情。

使用我真正想要的列表添加封装类:

using System.Xml.Serialization;

namespace DeserializeExample
{
    [XmlRoot("root")]
    public class BillingItemResult
    {
        [XmlElement("item")]
        public BillingItems Items { get; set; }
    }
}

然后在我的BillItems.cs类中,private static void方法将获取封装对象并返回它的计费项列表:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using System.Xml.Serialization;

namespace DeserializeExample
{
    [Serializable]
    [XmlRoot("root")]
    public class BillingItems : List<BillingItem>
    {
        public static BillingItems GetBillingItems()
        {
            using (TextReader reader = new StreamReader("BillingItems.xml"))
            {
                XmlSerializer serializer = new XmlSerializer(typeof(BillingItemResult));
                BillingItemResult billingItemResult = (BillingItemResult)serializer.Deserialize(reader);
                return billingItemResult.Items;
            }
        }
    }
}

这允许现有应用程序的设计和约定保持不变。以下是CLI的示例:

using System.Collections.Generic;
namespace DeserializeExample
{
    class Program
    {
        static void Main(string[] args)
        {
            BillingItems billingItems = BillingItems.GetBillingItems();
        }
    }
}

虽然这有效,但我仍然认为有一些更简单的东西不需要额外的包装类。