65.9K
CodeProject 正在变化。 阅读更多。
Home

通用 XML 序列化方法

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.11/5 (7投票s)

2009年4月28日

CPOL

3分钟阅读

viewsIcon

47838

downloadIcon

419

一个 XML 助手类, 可以使用 C# Generics 序列化和反序列化自定义用户对象

介绍 

我一直在寻找 XML 包装器来序列化和反序列化我的对象,但毫无结果。 显然,互联网上很少有能做到这一点的东西,除非你想使用像Karvonite 这样的完整对象状态管理解决方案,但与任何外部解决方案一样,它也会带来开销、错误等等。

我所寻找的是直观的简单,一种我可以重用的 XML Save | Load 方法,适用于任何对象类型。 来自 Devhood 的 Andrew Ma 撰写了一篇文章,解决了特定对象类型的问题。

但是,它没有考虑到以下几点

  1. 能够根据对象的类型自动命名 XML 文件。 这避免了程序员必须将他的 XML 文件名映射到他试图序列化的对象。
  2. 能够将任何对象传递给 XML 方法进行序列化和反序列化,而无需担心其类型(当然,前提是该对象是可序列化的,如果所有要序列化的字段都标有适当的XMLAttribute,例如类变量名为“password”的[XmlAttribute("Password")]。 请参阅图 1。)

    Correctly Serialized Class with XML Attributes

    图 1:正确序列化的类(带有 XmlAttribute)

  3. 保持 XmlSerializer 的状态(命名空间:System.Xml.Serialization),而无需为 Serialize 或 De-Serialize 方法重新初始化它。

为了实现上述目标,我利用 C# 的一个特性,称为泛型,以提供类型独立性,以便在任何 C# 应用程序中为任何可序列化对象利用我的 XML 帮助器类。

背景 

使用方法  

要运行代码,您需要 Visual Studio 2008 Express。 所有相应的导入和引用都已完成。

测试类(将被序列化为 XML)

我用来测试的 main 类文件称为 UserList,它主要包含一个 System.Collection.ArrayListUser 类,而 User 类又包含一堆原始 C# 数据类型。

这是一个很好的例子,可以测试可以说是复杂数据结构/类的自动序列化。

// UserList.cs 

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

namespace TESTXML
{
    // Shopping list class which will be serialized
    [XmlRoot("UserList")]
    public class UserList
    {
        private ArrayList myUserList;

        public UserList()
        {
            myUserList = new ArrayList();
        }              

        [XmlElement("myUsers")]
        public User[] myUsers
        {
            get
            {
                User[] myUsers = new User[myUserList.Count];
                myUserList.CopyTo(myUsers);
                return myUsers;
            }
            set
            {
                if (value == null) 
                    return;
                User[] myUsers = (User[])value;
                myUserList.Clear();
                foreach (User myUser in myUsers)
                    myUserList.Add(myUser);
            }
        }

        public string AddItem(User myUser)
        {
            myUserList.Add(myUser);
            return myUser.ToString();
        }
    }
}		

测试子类(也将自动序列化为 XML)

//User.cs 

public class User
{
    [XmlAttribute("UserName")]
    public String UserName = "";

    [XmlAttribute("Email")]
    public String Email = "";

    [XmlAttribute("Password")]
    public String Password = "";

    [XmlAttribute("TotalScore")]
    public int TotalScore = 0;

    [XmlAttribute("IsApproved")]
    public Boolean IsApproved = false;

    public User(string myUserName, String myEmail, String myPassword, 
				int myTotalScore, Boolean myIsApproved)
    {
        UserName = myUserName;
        Email = myEmail;
        Password = myPassword;
        TotalScore = myTotalScore;
        IsApproved = myIsApproved;
    }

    public override string ToString()
    {
        return "UserName: " + UserName + ", Email: " + Email + ", 
		TotalScore = " + TotalScore + ", IsApproved = " + IsApproved;
    }
} 

主要的 XML 帮助器类,可以将传递给它的任何类的任何可序列化对象进行序列化/反序列化

//Main File: XMLHelper.cs

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

namespace TESTXML
{
   public class XMLHelper <T>
    {
       XmlSerializer mySerializer ;
       String ClassName;
       String BaseDirectory;
       
       public XMLHelper()
       {
           mySerializer = new XmlSerializer(typeof(T));
           BaseDirectory = "";
       }

       public XMLHelper(String myBaseDirectory)
       {
           mySerializer = new XmlSerializer(typeof(T));
           BaseDirectory = myBaseDirectory;
       }

       public String FileName(T myObj)
       {
           ClassName = myObj.GetType().Name;
           return BaseDirectory + @"\" + ClassName + ".xml";           
       }

       public void Save(T myObj)
        {
            TextWriter myWriter = new StreamWriter(FileName(myObj));
            mySerializer.Serialize(myWriter, myObj);
            myWriter.Close();
        }

        public T Load(T myObj)
        {
            XmlSerializer mySerializer = new XmlSerializer(typeof(T));
            TextReader myReader = new StreamReader(FileName(myObj));
            T NewObject = (T)mySerializer.Deserialize(myReader);
            myReader.Close();
            return NewObject;
        }        
    }
}

关注点

public String FileName(T myObj)
{
    ClassName = myObj.GetType().Name;
    return BaseDirectory + "\\" + ClassName + ".xml";           
}

请注意在上面,我是如何使用 GetType 方法提取对象文件名的,以及一个概念性的反射概念,以便为相应的对象在相应的基本目录中自动生成一个 ***.xml 文件名。

这增加了一级可重用性,同时减少了程序员需要注意的一件事,即用于将磁盘上的 XML 文件名映射到用户对象的命名约定。 一个漂亮的小调整。

Using the Code

BaseDirectory 初始化为相对于项目默认输出目录的 XML 文件路径位置。

使用要调用的对象的类型实例化一个新的 XMLHelper 类,在本例中仅为类名。

稍后在任何时候,从 XMLHelper 类重新加载相同的对象。 (注意:XMLHelper 类可以重新实例化,您只需要基本目录,最终应该将其设置为项目设置。)

UserList myListOfUsers = new UserList();     
String BaseDirectory = "Data/XML"
XMLHelper<UserList>myXMLHelper = new XMLHelper<UserList>(BaseDirectory);
myListOfUsers = null;
//Load From BaseDirectory
myListOfUsers = (UserList)myXMLHelper.Load(myListOfUsers);

结果

创建/加载测试对象使用两个 User 初始化 UserList

序列化对象将刚刚创建的 UserList 对象序列化为 XML 并将其写入磁盘,同时重置该对象。

反序列化对象获取对象的 FilePath(通过简单地接受作为参数的 Object 类型,如上面 FileName 函数中所示),从磁盘读取到内存,从而重新填充 UserList 类的对象。

过程完成。

图 2:UserList 类序列化反序列化测试成功

您可以从本文顶部的链接下载附带的源代码和所有文件。

© . All rights reserved.