4.Dictionary支持Xml序列化反序列化

4.必备知识点-让Dictionary支持序列化反序列化


4.1 知识点

思考如何让Dictionary支持xml序列和反序列化

  • 我们没办法修改C#自带的类
  • 那我们可以重写一个类 继承Dictionary 然后让这个类继承序列化拓展接口IXmlSerializable
  • 实现里面的序列化和反序列化方法即可

让Dictionary支持序列化和反序列化

声明SerizlizerDictionary类,继承Dictionary和IXmlSerializable接口,实现自定义序列化反序列化字典

这是一个继承自Dictionary,实现了IXmlSerializable接口的自定义字典类型,用于XML序列化和反序列化键值对数据。

public class SerizlizerDictionary<TKey, TValue> : Dictionary<TKey, TValue>, IXmlSerializable
{
    // 返回空值。GetSchema方法是必须由接口 IXMlSerializable实现的方法,但在此类中不需要使用它。
    public XmlSchema GetSchema()
    {
        return null;
    }
    
    // 自定义字典类型(继承自Dictionary)的反序列化规则。接受一个XmlReader阅读器作为反序列化数据源。
    public void ReadXml(XmlReader xmlReader)
    {
        // 创建两个XmlSerializer实例,一个key的类型、一个是value的类型,用于反序列化XML流中的键值对数据。
        XmlSerializer keyXmlSerializer = new XmlSerializer(typeof(TKey));
        XmlSerializer valueXmlSerializer = new XmlSerializer(typeof(TValue));
        
        // 要跳过根节点
        xmlReader.Read();
        // 只要当前节点不为EndElement,则意味着还可以读取到新的节点,继续反序列化操作。
        while (xmlReader.NodeType != XmlNodeType.EndElement)
        {
            // 反序列化从XML阅读器读取的键对象,并进行强制类型转换到泛型TKey类别 
            TKey key = (TKey)keyXmlSerializer.Deserialize(xmlReader);
            // 反序列化从XML阅读器读取的值对象,并进行强制类型转换到泛型TValue类别 
            TValue value = (TValue)valueXmlSerializer.Deserialize(xmlReader);
            // 将键和值添加到字典中
            this.Add(key, value);
        }
        // 要跳过尾节点 避免影响之后的数据读取
        xmlReader.Read();
    }
    
    // 自定义字典类型的序列化规则。使用提供的XmlWriter实例将该字典序列化为XML。
    public void WriteXml(XmlWriter xmlWriter)
    {
        // 创建两个XmlSerializer实例,一个key的类型、一个是value的类型,用于序列化键值对数据。
        XmlSerializer keyXmlSerializer = new XmlSerializer(typeof(TKey));
        XmlSerializer valueXmlSerializer = new XmlSerializer(typeof(TValue));
        
        // 使用foreach循环安全遍历字典中所有的键值对象,并依次将其序列化到由writer引用的输出流中。
        foreach (KeyValuePair<TKey, TValue> kv in this)
        {
            // 序列化键和值到writer流。
            keyXmlSerializer.Serialize(xmlWriter, kv.Key);
            valueXmlSerializer.Serialize(xmlWriter, kv.Value);
        }
    }
}

创建TestLesson4,用于测试自定义序列化字典的序列化和反序列化

在TestLesson4类定义了一个公共int类型成员test1,“SerizlizerDictionary<int, string>”自定义字典类型变量serizlizerDictionary。

public class TestLesson4
{
    public int test1; // 定义一个公共int类型变量 test1.
    public SerizlizerDictionary<int, string> serizlizerDictionary;//自定义一个 字典 类型 serizlizerDictionary.
}

测试TestLesson4实例的序列化和反序列化

void Start()
{
    // 先通过创建TestLesson4类类型变量testLesson4_1并为其 serizlizerDictionary 成员 添加了三个键值对数据,调用Application对象的 persistentDataPath 成员获取应用程序数据路径,使用StreamWriter类打开要输出的文件流
    TestLesson4 testLesson4_1 = new TestLesson4();
    testLesson4_1.serizlizerDictionary = new SerizlizerDictionary<int, string>();
    
    // 向 serizlizerDictionary 添加三个键值对。
    testLesson4_1.serizlizerDictionary.Add(1, "123");
    testLesson4_1.serizlizerDictionary.Add(2, "234");
    testLesson4_1.serizlizerDictionary.Add(3, "345");
    
    // 通过Application对象的 persistentDataPath 成员获取用于存储数据文件的路径。并将路径记录在日志中以进行调试验证.
    string path = Application.persistentDataPath + "/TestLesson4.xml";
    Debug.Log(path);
    
    // 使用StreamWriter类为指定的文件建立新的编写器,并使用测试程序运行时序列化器生成 XML 文档。然后将XML文档提交给StreamWriter文本流进行保存。
    using (StreamWriter streamWriter = new StreamWriter(path))
    {
        XmlSerializer xmlSerializer = new XmlSerializer(typeof(TestLesson4));
        xmlSerializer.Serialize(streamWriter, testLesson4_1);
    }
    
    // 接下来我们要反序列化上面序列化的文件,将XML数据中的内容读取到一个新的 TestLesson4实例 对象testLesson4_2中
    TestLesson4 testLesson4_2 = new TestLesson4();
    
    // 使用StreamReader打开创建的存成XML格式的文件,XmlSerializer生成适当的类以反序列化 XML 文档,动态将其转换为 TestLesson4 类型,然后将反序列化得到TestLesson4对象的应用返回到 testLesson4_2.
    using (StreamReader streamReader = new StreamReader(path))
    {
        XmlSerializer xmlSerializer = new XmlSerializer(typeof(TestLesson4));
        testLesson4_2 = xmlSerializer.Deserialize(streamReader) as TestLesson4;
    }
    
    // 至此,整个操作过程完成,TestLesson4 对象已被序列化为XML,再通过反序列化将XML数据导入了一个新的TestLesson4实例对象testLesson4_2中。
}

验证序列化和反序列化

查看路径下序列化的xml文件

<?xml version="1.0" encoding="utf-8"?>
<TestLesson4 xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <test1>0</test1>
  <serizlizerDictionary>
    <int>1</int>
    <string>123</string>
    <int>2</int>
    <string>234</string>
    <int>3</int>
    <string>345</string>
  </serizlizerDictionary>
</TestLesson4>

断点查看反序列化是否成功


4.2 知识点代码

SerizlizerDictionary

using System.Collections;
using System.Collections.Generic;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
using UnityEngine;

// 这是一个继承自Dictionary,实现了IXmlSerializable接口的自定义字典类型,用于XML序列化和反序列化键值对数据。
public class SerizlizerDictionary<TKey, TValue> : Dictionary<TKey, TValue>, IXmlSerializable
{
    // 返回空值。GetSchema方法是必须由接口 IXMlSerializable实现的方法,但在此类中不需要使用它。
    public XmlSchema GetSchema()
    {
        return null;
    }

    // 自定义字典类型(继承自Dictionary)的反序列化规则。接受一个XmlReader阅读器作为反序列化数据源。
    public void ReadXml(XmlReader xmlReader)
    {
        // 创建两个XmlSerializer实例,一个key的类型、一个是value的类型,用于反序列化XML流中的键值对数据。
        XmlSerializer keyXmlSerializer = new XmlSerializer(typeof(TKey));
        XmlSerializer valueXmlSerializer = new XmlSerializer(typeof(TValue));

        // 要跳过根节点
        xmlReader.Read();
        // 只要当前节点不为EndElement,则意味着还可以读取到新的节点,继续反序列化操作。
        while (xmlReader.NodeType != XmlNodeType.EndElement)
        {
            // 反序列化从XML阅读器读取的键对象,并进行强制类型转换到泛型TKey类别 
            TKey key = (TKey)keyXmlSerializer.Deserialize(xmlReader);
            // 反序列化从XML阅读器读取的值对象,并进行强制类型转换到泛型TValue类别 
            TValue value = (TValue)valueXmlSerializer.Deserialize(xmlReader);
            // 将键和值添加到字典中
            this.Add(key, value);
        }
        // 要跳过尾节点 避免影响之后的数据读取
        xmlReader.Read();
    }

    // 自定义字典类型的序列化规则。使用提供的XmlWriter实例将该字典序列化为XML。
    public void WriteXml(XmlWriter xmlWriter)
    {
        // 创建两个XmlSerializer实例,一个key的类型、一个是value的类型,用于序列化键值对数据。
        XmlSerializer keyXmlSerializer = new XmlSerializer(typeof(TKey));
        XmlSerializer valueXmlSerializer = new XmlSerializer(typeof(TValue));

        // 使用foreach循环安全遍历字典中所有的键值对象,并依次将其序列化到由writer引用的输出流中。
        foreach (KeyValuePair<TKey, TValue> kv in this)
        {
            // 序列化键和值到writer流。
            keyXmlSerializer.Serialize(xmlWriter, kv.Key);
            valueXmlSerializer.Serialize(xmlWriter, kv.Value);
        }
    }
}

Lesson04_必备知识点_让Dictionary支持序列化反序列化

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

// 在TestLesson4类定义了一个公共int类型成员test1,“SerizlizerDictionary<int, string>”自定义字典类型变量serizlizerDictionary。
public class TestLesson4
{
    public int test1; // 定义一个公共int类型变量 test1.
    public SerizlizerDictionary<int, string> serizlizerDictionary;//自定义一个 字典 类型 serizlizerDictionary.

}

public class Lesson04_必备知识点_让Dictionary支持序列化反序列化 : MonoBehaviour
{
    void Start()
    {
        #region 知识点一 思考如何让Dictionary支持xml序列和反序列化
        //1.我们没办法修改C#自带的类
        //2.那我们可以重写一个类 继承Dictionary 然后让这个类继承序列化拓展接口IXmlSerializable
        //3.实现里面的序列化和反序列化方法即可
        #endregion

        #region 知识点二 让Dictionary支持序列化和反序列化

        // 先通过创建TestLesson4类类型变量testLesson4_1并为其 serizlizerDictionary 成员 添加了三个键值对数据,调用Application对象的 persistentDataPath 成员获取应用程序数据路径,使用StreamWriter类打开要输出的文件流
        TestLesson4 testLesson4_1 = new TestLesson4();
        testLesson4_1.serizlizerDictionary = new SerizlizerDictionary<int, string>();

        // 向 serizlizerDictionary 添加三个键值对。
        testLesson4_1.serizlizerDictionary.Add(1, "123");
        testLesson4_1.serizlizerDictionary.Add(2, "234");
        testLesson4_1.serizlizerDictionary.Add(3, "345");

        // 通过Application对象的 persistentDataPath 成员获取用于存储数据文件的路径。并将路径记录在日志中以进行调试验证.
        string path = Application.persistentDataPath + "/TestLesson4.xml";
        Debug.Log(path);

        // 使用StreamWriter类为指定的文件建立新的编写器,并使用测试程序运行时序列化器生成 XML 文档。然后将XML文档提交给StreamWriter文本流进行保存。
        using (StreamWriter streamWriter = new StreamWriter(path))
        {
            XmlSerializer xmlSerializer = new XmlSerializer(typeof(TestLesson4));
            xmlSerializer.Serialize(streamWriter, testLesson4_1);
        }

        // 接下来我们要反序列化上面序列化的文件,将XML数据中的内容读取到一个新的 TestLesson4实例 对象testLesson4_2中
        TestLesson4 testLesson4_2 = new TestLesson4();

        // 使用StreamReader打开创建的存成XML格式的文件,XmlSerializer生成适当的类以反序列化 XML 文档,动态将其转换为 TestLesson4 类型,然后将反序列化得到TestLesson4对象的应用返回到 testLesson4_2.
        using (StreamReader streamReader = new StreamReader(path))
        {
            XmlSerializer xmlSerializer = new XmlSerializer(typeof(TestLesson4));
            testLesson4_2 = xmlSerializer.Deserialize(streamReader) as TestLesson4;
        }

        // 至此,整个操作过程完成,TestLesson4 对象已被序列化为XML,再通过反序列化将XML数据导入了一个新的TestLesson4实例对象testLesson4_2中。

        #endregion
    }
}

TestLesson4.xml

<?xml version="1.0" encoding="utf-8"?>
<TestLesson4 xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <test1>0</test1>
  <serizlizerDictionary>
    <int>1</int>
    <string>123</string>
    <int>2</int>
    <string>234</string>
    <int>3</int>
    <string>345</string>
  </serizlizerDictionary>
</TestLesson4>


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏