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

.NET 4 的可序列化额外类型

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.85/5 (9投票s)

2011年5月25日

GPL3

3分钟阅读

viewsIcon

74812

downloadIcon

350

用于快速应用程序开发的序列化。

您可以关注此代码 @ serializableex.codeplex.com

引言

这是对我最初在 CodeProject 上发布的文章 [用于快速应用程序开发的序列化:一种更好的方法] 的更新文章和代码库。 经过几年的能力增长和技术进步,我决定是时候更新该代码库和文章以用于 .NET 4 了。 结果是一个小得多的代码库、支持它们的单元测试以及修复了一些关于 Web 环境中发现的问题。

背景

简而言之,当我写第一篇文章时存在的 XmlSerializer 的问题今天仍然存在。 它们是经典问题,仍然没有统一的处理方法。 主要问题仍然是如何在序列化和反序列化时解析未知类。

多年来,我一直关注几种试图绕过这个问题的尝试,从创建像 YAXLib 这样的整个框架,到关于如何在不同复杂程度级别上使用 IXmlSerializable 接口的说明。

对于所有这些解决方案,从开发人员的角度来看,一直存在的主要问题是实现的繁琐性。 IXmlSerializable 要求开发人员为每个类编写某种形式的定制实现。 YAXLib 和其他库要求开发人员使用不同的属性,或者处理看起来不像 XmlSerializer 生成的干净(ish)XML 的输出。 [XmlInclude(Type type)] 属性要求所有要序列化的类型都必须在同一个库中。 我认为,它们(据我所知)都不能减轻开发人员使用这些解决方案的乏味。

实现的目标

Serializable Extra Types 的设计尽可能简单,并且最大限度地减少开发考虑。 它所做的是利用标准的 XmlSerializer 和稍微不为人知(un-hyped)的重载构造函数; 它必须包含额外的类型定义,以便在序列化和反序列化期间用于类型解析。

这实际上是一个非常简单的想法。 保留 XmlSerializer 在序列化/反序列化过程中可能需要的所有可能类型的列表。 使用属性修饰注册这些类型,并提供一些扩展方法,使开发人员可以轻松地将这些列表合并进来。

它在父子关系下工作。 我可以用最好的方式来描述它,那就是说,它是 XmlInclude 属性的反面。 XmlInclude 属性放置在一个类上,以便在序列化被修饰的类时让序列化器了解其他类。 SerializableExtraType 放置在一个类上,以便在序列化另一个类时让该类了解被修饰的类。

那么...

XmlInclude = Parent => Child
SerializableExtraType = Child => Parent

这允许 SerializableExtraTypes 代码集成跨库的相关类。 此外,我公开了一种方法,您可以在运行时注册其他关系。 这解决了您在库和应用程序具有复杂隐含关系时可能遇到的任何情况。

使用代码

代码可在下载中和 CodePlex 站点上获得。 两者都有一系列测试库和一个使用它的测试项目,可以很好地显示用法。 在这里,我将概述如何快速而粗略地使用它。

首先,使用所需的属性修饰一个类,如下所示

// example 1 of registering class and all derived classes
[SerializableExtraType(typeof(Foo))]
// example 2 of registering class with an unrelated class
[SerializableExtraType(typeof(SomethingElse))]
// example 3 of registering with multiple classes in same attribute
[SerializableExtraType(typeof(ClassOne), typeof(ClassTwo))]
public class Foo { public Foo() {} }

扩展方法使用 System.Xml.Serialization 下的 SerializableExtraTypes

现在使用扩展方法来序列化和反序列化对象。

// example 1 assuming that ClassOne and ClassTwo inherit from Foo
string xml = new Foo { ClassList = {new ClassOne(), new ClassTwo(), }, }.SerializeEx();
Foo obj = "<Foo><ClassList><ClassOne /><ClassTwo /></Foo>".DeserializeEx<Foo>();

// example 2 assuming that Foo bears no relationship with SomethingElse
string xml = new SomethingElse { ObjectList = { new Foo(), new Foo(), }, }.SerializeEx();
SomethingElse obj = "<SomethingElse><ArrayOfObject><Foo />" + 
   "<Foo /></ArrayOfObject></SomethingElse>".DeserializeEx<SomethingElse>();

代码库中内置了更多功能,但这只是一个快速而粗略的示例。 请查看下载以获取更多示例。

历史

这是该方法的第二版发布。 请发送任何意见或建议,以改进它。 您可以通过 danatcofo@gmail.com 给电子邮件给我。

© . All rights reserved.