如何将简单类序列化/反序列化为XML并返回

29
有时候我想模拟我的类的存储数据,而不需要进行往返数据库的操作。比如说,假设我有以下这些类:
public class ShoppingCart
{
    public List<CartItem> Items {get; set;}
    public int UserID { get; set; }
}

public class CartItem
{
    public int SkuID { get; set; }
    public int Quantity  { get; set; }
    public double ExtendedCost  { get; set; }
}

假设我在内存中构建了一个ShoppingCart对象,并希望将其“保存”为XML文档。是否可以通过某种XDocument.CreateFromPOCO(shoppingCart)方法实现?那么反过来呢:是否有一种内置的方式可以通过像new ShoppingCart(xDoc)这样的XML文档创建ShoppingCart对象?

4个回答

62

XmlSerializer 是其中一种方法,DataContractSerializer 是另一种方法。使用 XmlSerializer 的示例:

using System.Xml;
using System.Xml.Serialization;

//...

ShoppingCart shoppingCart = FetchShoppingCartFromSomewhere();
var serializer = new XmlSerializer(shoppingCart.GetType());
using (var writer = XmlWriter.Create("shoppingcart.xml"))
{
    serializer.Serialize(writer, shoppingCart);
}

并且将其反序列化回去:

var serializer = new XmlSerializer(typeof(ShoppingCart));
using (var reader = XmlReader.Create("shoppingcart.xml"))
{
    var shoppingCart = (ShoppingCart)serializer.Deserialize(reader);
}

为了更好地封装,我建议您在 CartItem 类中使用属性而不是字段。


谢谢建议。我本来想使用属性而不是字段的。已经修复了。 - Ben McCormack
我花了一些时间才开始测试,但它完美地工作了。谢谢! - Ben McCormack
3
我希望我能为这几个星期里每次打开这个答案给你点赞。它一直很有帮助! - Ben McCormack

13

做得好。这里是将普通POCO序列化为字符串的示例。

    private string poco2Xml(object obj)
    {
        XmlSerializer serializer = new XmlSerializer(obj.GetType());
        StringBuilder result = new StringBuilder();
        using (var writer = XmlWriter.Create(result))
        {
            serializer.Serialize(writer, obj);
        }
        return result.ToString();
    }

3
您可以使用XmlSerializerDataContractSerializer进行序列化/反序列化。
在您的类上添加DataContractDataMember属性注释,并编写如下代码将其序列化为XML格式并保存到文件中。
ShoppingCart cart = ...
using(FileStream writer = new FileStream(fileName, FileMode.Create))
{
   DataContractSerializer ser = new DataContractSerializer(typeof(ShoppingCart));
   ser.WriteObject(writer, cart);
}

1
@Darin:当你开始使用DataContractSerializer时,你经常会遇到这个问题。但它通常归结为对你的类进行属性注释。XmlSerializer更容易使用,因为它几乎可以处理任何你投入其中的东西,但DataContractSerializer更快,但需要更多的“工作”才能使其运行。 - Mikael Svenson
@Mikael,我觉得你没有理解我的意思。我的意思是,如果抛出异常,你将会泄露一个文件句柄,这非常糟糕,因为它会锁定该文件,直到你杀死应用程序之前,其他进程都无法对其进行任何操作。 - Darin Dimitrov
@Darin:刚刚进行了编辑,我需要在代码示例中提高编写生产代码质量的能力,而不仅仅是解决问题。 - Mikael Svenson
2
@Mikael,StackOverflow是一个非常有参考价值的网站,这意味着你在这里写的内容可能会被许多人在生产代码中不负责任地使用。我认为,像释放可释放资源这样的基本事项是避免推广不良实践的最低要求。我相信有很多人只是从博客文章中复制粘贴,甚至没有意识到这可能对他们的生产系统造成灾难性的影响。 - Darin Dimitrov
1
@Darin:确实如此。我实际上是从MSDN复制/粘贴我的代码并进行修改的,所以他们在示例中也有工作要做。除了示例是控制台应用程序,因此任何文件锁定都将在程序“崩溃”时处理。 - Mikael Svenson
显示剩余3条评论

0
只需使用 [XmlElement(name)](或 XmlAttribute、XmlRoot 等)标记要序列化的内容,然后使用 XmlSerializer 即可。如果需要非常自定义的格式,请实现 IXmlSerializable 接口。

2
为什么不像帖子上的其他答案一样提供一个代码示例呢? - Konstantin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接