Unity数据持久化
三、XML数据持久化
3.5 IXmlSerializable接口
3.5.1 IXmlSerializable接口基础概念
什么是IXmlSerializable接口:
IXmlSerializable
是.NET框架提供的一个接口,允许类自定义XML序列化和反序列化的过程。当默认的XML序列化行为无法满足需求时,可以实现这个接口来完全控制XML的读写过程。
接口定义:
csharp
public interface IXmlSerializable
{
XmlSchema GetSchema();
void ReadXml(XmlReader reader);
void WriteXml(XmlWriter writer);
}
核心方法说明:
- GetSchema():返回XML架构定义,通常返回null
- ReadXml(XmlReader reader):自定义XML反序列化过程
- WriteXml(XmlWriter writer):自定义XML序列化过程
3.5.2 实现IXmlSerializable接口
基本实现结构:
csharp
using System.Xml.Serialization;
using System.Xml;
using System.Xml.Schema;
public class TextData : IXmlSerializable
{
public string text = "gsffs";
public int age;
public List<string> list;
public int[] array = new int[3] { 1, 2, 3 };
// 实现IXmlSerializable接口
public XmlSchema GetSchema()
{
return null; // 通常返回null
}
public void ReadXml(XmlReader reader)
{
// 自定义反序列化逻辑
}
public void WriteXml(XmlWriter writer)
{
// 自定义序列化逻辑
}
}
3.5.3 自定义XML序列化(WriteXml方法)
WriteXml方法用于控制对象如何序列化为XML格式。有三种主要的写入方式:
1. 写入属性(Attribute)
csharp
public void WriteXml(XmlWriter writer)
{
// 将数据作为XML元素的属性写入
writer.WriteAttributeString("text", text);
writer.WriteAttributeString("age", age.ToString());
}
生成的XML格式:
xml
<TextData text="gsffs" age="25" />
2. 写入元素节点(Element)
csharp
public void WriteXml(XmlWriter writer)
{
// 将数据作为独立的XML元素写入
writer.WriteElementString("text", text);
writer.WriteElementString("age", age.ToString());
}
生成的XML格式:
xml
<TextData>
<text>gsffs</text>
<age>25</age>
</TextData>
3. 写入包裹节点(复杂序列化)
csharp
public void WriteXml(XmlWriter writer)
{
// 使用XmlSerializer进行复杂类型的序列化
XmlSerializer ser = new XmlSerializer(typeof(string));
// 写入text字段
writer.WriteStartElement("text1");
ser.Serialize(writer, text);
writer.WriteEndElement();
// 写入age字段
XmlSerializer ser2 = new XmlSerializer(typeof(int));
writer.WriteStartElement("age");
ser2.Serialize(writer, age);
writer.WriteEndElement();
}
生成的XML格式:
xml
<TextData>
<text1>gsffs</text1>
<age>25</age>
</TextData>
3.5.4 自定义XML反序列化(ReadXml方法)
ReadXml方法用于控制如何从XML格式反序列化为对象。有三种主要的读取方式:
1. 读取属性(Attribute)
csharp
public void ReadXml(XmlReader reader)
{
// 从XML元素的属性中读取数据
age = int.Parse(reader.GetAttribute("age"));
text = reader.GetAttribute("text");
}
2. 读取元素节点(Element)
csharp
public void ReadXml(XmlReader reader)
{
// 方法1:手动控制读取过程
reader.Read(); // 读取text节点
reader.Read(); // 读取text包裹内容
text = reader.Value;
reader.Read(); // 读取text末节点
reader.Read(); // 读取age节点
reader.Read(); // 读取age包裹内容
age = int.Parse(reader.Value);
reader.Read(); // 读取age末节点
}
3. 使用循环读取多个元素
csharp
public void ReadXml(XmlReader reader)
{
// 方法2:使用循环遍历所有元素
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element)
{
switch (reader.Name)
{
case "text":
reader.Read();
text = reader.Value;
break;
case "age":
reader.Read();
age = int.Parse(reader.Value);
break;
}
}
}
}
4. 读取包裹节点(复杂反序列化)
csharp
public void ReadXml(XmlReader reader)
{
// 使用XmlSerializer进行复杂类型的反序列化
XmlSerializer ser3 = new XmlSerializer(typeof(string));
XmlSerializer ser4 = new XmlSerializer(typeof(int));
reader.Read(); // 跳过根节点
reader.ReadStartElement();
text = (string)ser3.Deserialize(reader);
reader.ReadEndElement();
reader.Read();
reader.ReadStartElement();
age = (int)ser4.Deserialize(reader);
reader.ReadEndElement();
}
3.5.5 完整的IXmlSerializable实现示例
基于您的代码的完整实现:
csharp
using UnityEngine;
using System.Xml.Serialization;
using System.IO;
using System.Xml;
using System.Xml.Schema;
using System.Collections.Generic;
/// <summary>
/// 自定义XML序列化的数据类
/// 实现IXmlSerializable接口以完全控制XML读写过程
/// </summary>
public class TextData : IXmlSerializable
{
public string text = "gsffs";
public int age;
public List<string> list;
public int[] array = new int[3] { 1, 2, 3 };
/// <summary>
/// 返回XML架构定义
/// </summary>
/// <returns>通常返回null</returns>
public XmlSchema GetSchema()
{
return null;
}
/// <summary>
/// 自定义XML反序列化过程
/// </summary>
/// <param name="reader">XML读取器</param>
public void ReadXml(XmlReader reader)
{
// 使用XmlSerializer进行复杂类型的反序列化
XmlSerializer ser3 = new XmlSerializer(typeof(string));
XmlSerializer ser4 = new XmlSerializer(typeof(int));
reader.Read(); // 跳过根节点
reader.ReadStartElement();
text = (string)ser3.Deserialize(reader);
reader.ReadEndElement();
reader.Read();
reader.ReadStartElement();
age = (int)ser4.Deserialize(reader);
reader.ReadEndElement();
}
/// <summary>
/// 自定义XML序列化过程
/// </summary>
/// <param name="writer">XML写入器</param>
public void WriteXml(XmlWriter writer)
{
// 使用XmlSerializer进行复杂类型的序列化
XmlSerializer ser = new XmlSerializer(typeof(string));
writer.WriteStartElement("text1");
ser.Serialize(writer, text);
writer.WriteEndElement();
XmlSerializer ser2 = new XmlSerializer(typeof(int));
writer.WriteStartElement("age");
ser2.Serialize(writer, age);
writer.WriteEndElement();
}
}
/// <summary>
/// IXmlSerializable接口测试类
/// 演示如何使用自定义XML序列化
/// </summary>
public class XmlSerilizef : MonoBehaviour
{
void Start()
{
// 设置存储路径
string path = Application.persistentDataPath + "/TextData.xml";
print("存储路径: " + path);
// 创建测试数据
TextData textData = new TextData();
textData.list = new List<string>() { "1", "2", "3" };
textData.age = 25;
// 序列化对象到XML文件
XmlSerializer ser444 = new XmlSerializer(typeof(TextData));
using (StreamWriter sw = new StreamWriter(path))
{
ser444.Serialize(sw, textData);
}
// 从XML文件反序列化对象
TextData textData2;
using (StreamReader sr = new StreamReader(path))
{
textData2 = (TextData)ser444.Deserialize(sr);
}
// 验证反序列化结果
if (textData2 != null)
{
print("反序列化成功!");
print("文本: " + textData2.text);
print("年龄: " + textData2.age);
}
}
}
3.5.6 IXmlSerializable接口的优势和应用场景
优势:
- 完全控制:可以完全控制XML的读写过程
- 灵活性:支持复杂的XML结构和自定义格式
- 性能优化:可以针对特定需求优化序列化性能
- 兼容性:可以处理不同版本的XML格式
应用场景:
- 复杂数据结构:当默认序列化无法处理复杂的数据结构时
- 自定义格式:需要生成特定格式的XML时
- 性能要求:对序列化性能有特殊要求时
- 版本兼容:需要处理不同版本的XML格式时
3.5.7 注意事项和最佳实践
1. 实现要求
csharp
// 必须实现所有三个方法
public XmlSchema GetSchema() { return null; }
public void ReadXml(XmlReader reader) { /* 自定义读取逻辑 */ }
public void WriteXml(XmlWriter writer) { /* 自定义写入逻辑 */ }
2. 错误处理
csharp
public void ReadXml(XmlReader reader)
{
try
{
// 自定义读取逻辑
reader.Read();
text = reader.Value;
}
catch (System.Exception e)
{
Debug.LogError("XML读取失败: " + e.Message);
}
}
通过实现 IXmlSerializable
接口,可以为Unity项目提供高度自定义的XML序列化解决方案,特别适合需要精确控制XML格式的复杂应用场景。