自定义 .NET 序列化 - 第三部分






1.67/5 (3投票s)
本文将概述如何实现自己的序列化引擎。
引言
在我上一篇文章中,我介绍了 .NET 中可用的各种序列化技术。在本文中,我将概述如何实现自己的序列化引擎。
背景
本文是之前文章的延续 - 自定义序列化 - 第二部分。
序列化引擎
当 .NET 默认提供序列化时,我们为什么需要开发自定义解决方案?嗯,这样做可以实现一些功能,它们是:
- 能够动态控制要序列化或不序列化的属性。这将帮助我们仅序列化用户根据授权角色和规则允许查看的属性。
- 能够动态控制序列化数据的格式。例如,动态地将对象序列化为 XML 元素或 XML 属性。
- 由于格式由我们控制,并且可以与其他平台共享相同的格式,因此在企业内部与其他平台进行互操作要容易得多。
现在我们已经确定了自定义序列化引擎的“为什么”和“好处”,我们将研究构建它的步骤。序列化引擎会将对象序列化为 XML 字符串,并将 XML 字符串反序列化回对象。该引擎将能够为任何对象执行此操作。该引擎通过获取属性列表并将它们根据配置文件转换为 XML 字符串来实现。为了方便起见,我将其称为映射文件。
映射文件将帮助引擎将对象转换为 XML,反之亦然。映射文件将包含以下信息来实现这一点:
- 对象信息,例如 - 类名、类型、程序集、架构文件
- 属性列表
- 属性数据类型
- XML 文档中每个属性的 XPath
下面是 Customer
对象的映射文件
下面是 Customer
对象的架构文件
架构文件将定义 Customer 对象序列化为 XML 时的格式。在此示例中,Customer
对象的属性定义为 XML 元素。我们还可以将映射文件与每个属性 XPath 的架构文件关联起来。
序列化逻辑
现在,我们已经完成了基础工作,可以开始实现自定义序列化引擎了。序列化逻辑如下:
- 接受对象和映射文件名作为参数
- 加载映射 XML 文件
- 根据映射文件中的
schemaFile
属性值,从 XSD 文件生成一个空 XML - 循环遍历“serializer/object/properties”定义的所有属性
- 对于每个节点,获取名称并从实例的属性 getter 获取值
- 根据 XPath 在 XML 中设置值
- 对映射文件中的每个属性执行步骤 4 a、b
- XML 文档现在包含传入实例的 XML 表示形式
以下代码片段显示了序列化逻辑
public string Serialize(object instance, string mappingFile)
{
Mapper mapper = Mapper.GetMappingFile(mappingFile);
string xml = Serializer.GenerateXml(mapper.DataObject.SchemaFile);
XmlDocument document = new XmlDocument();
document.LoadXml(xml);
Type type = instance.GetType();
foreach (DataObjectProperty property in mapper.DataObject.Properties)
{
object oValue = type.InvokeMember(property.Name, BindingFlags.GetProperty |
BindingFlags.Instance | BindingFlags.Public, null, instance, null);
string value = oValue.ToString();
XmlNode node = document.SelectSingleNode(property.Xpath);
node.InnerXml = value;
}
return document.ChildNodes[1].OuterXml;
}
Mapper
是表示映射文件的强类型类。映射 XML 文件被形成一个强类型实例并加载到 Hashtable
中。这避免了对每个序列化逻辑重新加载 XML 文件,并提高了性能。
从 XSD 生成 XML
为了从给定的 XSD 文件生成空 XML,我使用了这个MSDN 文章中的代码。它接受一个 XSD 文件并返回一个空 XML。请参阅代码下载附带的 Microsoft.Xml.XMLGen 项目。
private static string GenerateXml(string schemaFile)
{
StringBuilder builder = new StringBuilder();
XmlWriter writer = XmlWriter.Create(builder);
XmlSampleGenerator xmlGenerator =
new XmlSampleGenerator(schemaFile, null);
xmlGenerator.WriteXml(writer);
string xml = builder.ToString();
return xml;
}
反序列化逻辑
反序列化逻辑将与序列化逻辑完全相反
- 接受 XML 字符串和映射文件名作为参数
- 加载映射 XML 文件
- 加载 XML 字符串
- 根据映射文件中的
schemaFile
属性值,加载程序集并创建实例 - 循环遍历“serializer/object/properties”定义的所有属性
- 对于每个节点,获取名称,并为实例的属性 setter 设置值
- 对映射文件中的每个属性执行步骤 5 a
- XML 文档现在包含传入实例的 XML 表示形式
以下代码片段显示了反序列化逻辑
public object Deserialize(string xmlData, string mappingFile)
{
XmlDocument document = new XmlDocument();
document.LoadXml(xmlData);
Mapper mapper = Mapper.GetMappingFile(mappingFile);
Assembly assembly = Assembly.Load(mapper.DataObject.Assembly);
object instance = assembly.CreateInstance(mapper.DataObject.Type);
Type type = instance.GetType();
foreach (DataObjectProperty property in mapper.DataObject.Properties)
{
XmlNode node = document.SelectSingleNode(property.Xpath);
if ( property.NodeType ==
string value = node.InnerXml;
Type memberType = type.GetProperty(property.Name,
BindingFlags.Instance | BindingFlags.Public).PropertyType;
object oFinalValue = Convert.ChangeType(value, memberType);
type.InvokeMember(property.Name, BindingFlags.SetProperty | BindingFlags.Instance |
BindingFlags.Public, null, instance, new object[] { oFinalValue });
}
return instance;
}
关于示例应用程序
示例应用程序包含一个客户表单,该表单接受数据以形成客户实例。序列化按钮将客户对象序列化为 XML 字符串并在结果文本框中显示。反序列化按钮从结果文本框中的 XML 中创建对象并在控件中显示。
调用序列化过程
CustomSerializer.Serializer serializer = new CustomSerializer.Serializer();
textBoxResult.Text = serializer.Serialize(customer, mappingFile);
调用反序列化过程
CustomSerializer.Serializer serializer = new CustomSerializer.Serializer();
Customer customer = (Customer)serializer.Deserialize(textBoxResult.Text, mappingFile);
应用程序快照
编码愉快,阅读愉快!