c#

位置:IT落伍者 >> c# >> 浏览文章

对.NET Framework 反射的反思[4]


发布日期:2018年08月25日
 
对.NET Framework 反射的反思[4]

如果事先完全了解需要转换的正式数据类型(例如自己编写代码时)事情就变得非常简单

foreach(Address a in AddressList)

{

ConsoleWriteLine(Address:{} aID);

ConsoleWriteLine(\tStreet:{} aStreet);

// and so on

}

然而如果预先不知道在运行时会遇到的数据类型情况会变得十分有趣您如何编写象这样的一般框架代码?

MyFrameworkTranslateObject(object input MyOutputWriter output)

首先您需要决定哪些类型成员对序列化有用可能的情况包括仅捕获特定类型的成员例如基元系统类型或提供一种机制以供类型作者说明哪些成员需要被序列化例如在类型成员上使用自定义属性作为标记)您仅可以捕获特定类型的成员例如基元系统类型或类型作者能够说明哪些成员需要被序列化(可能的方法是在类型成员上使用自定义属性作为标记)

一旦记录清楚需要转换的数据结构成员您接着需要做的是编写逻辑从传入的对象枚举和检索它们反射在这里担负了繁重的任务让您既可以查询数据结构又可以查询数据值

出于简单性考虑我们来设计一个轻型转换引擎得到一个对象获取所有其公共属性值通过直接调用 ToString 将它们转换成字符串然后将这些值序列化对于一个名为input的给定对象算法大致如下

调用 inputGetType 以检索 SystemType 实例该实例描述了 input 的底层结构

用 TypeGetProperties 和适当的 BindingFlags 参数将公共属性作为 PropertyInfo 实例检索

使用 PropertyInfoName 和 PropertyInfoGetValue将属性作为键值对检索

在每个值上调用 ObjectToString 将其(通过基本方式)转化为字符串格式

将对象类型的名称和属性名称字符串值的集合打包成正确的序列化格式

这一算法明显简化了事情同时也抓住了得到运行时数据结构并将其转化为自描述型数据的要旨但这里有一个问题性能之前提到反射对于类型处理和值检索的成本都很高本示例中我在每个提供类型的实例中执行了完整的类型分析

如果以某种方式可以捕获或保留您对于类型结构的理解以便日后不费力地检索它并有效处理该类型的新实例;换句话说就是往前跳到示例算法中的步骤 #?好消息是利用 NET Framework 中的功能完全可能做到这一点一旦您理解了类型的数据结构便可以使用 CodeDom 动态生成绑定到该数据结构的代码您可以生成一个帮助器程序集其中包含帮助器类和引用了传入类型并直接访问其属性的方法(类似托管代码中的任何其他属性)因此类型检查只会对性能产生一次影响

现在我将修正这一算法新类型

获得对应于该类型的 SystemType 实例

使用各种 SystemType 访问器检索架构(或至少检索对序列化有用的架构子集)例如属性名称字段名称等

使用架构信息生成帮助器程序集(通过 CodeDom)该程序集与新类型相链接并有效地处理实例

在帮助器程序集中使用代码提取实例数据

根据需要序列化数据

对于给定类型的所有传入数据可以往前跳到步骤 #较之显式检查每一实例这么做可以获得巨大的性能提升

我开发了一个名为 SimpleSerialization 的基本序列化库它用反射和 CodeDom(本专栏中可下载)实现了这一算法主要组件是一个名为 SimpleSerializer 的类是用户用一个 SystemType 实例构造所得在构造函数中新的 SimpleSerializer 实例会分析给定的类型利用帮助器类生成一个临时程序集该帮助器类会紧密绑定到给定的数据类型而且对实例的处理方式就象自己在完全事先了解类型的情况下编写代码那样

SimpleSerializer 类有如下布局

class SimpleSerializer

{

public class SimpleSerializer(Type dataType);

public void Serialize(object input SimpleDataWriter writer);

}

简单地令人惊歎!构造函数承担了最繁重的任务它使用反射来分析类型结构然后用 CodeDom 生成帮助器程序集SimpleDataWriter 类只是用来阐明常见序列化模式的数据接收器

要序列化一个简单的 Address 类实例用下面的伪代码即可完成任务

SimpleSerializer mySerializer = new SimpleSerializer(typeof(Address));

SimpleDataWriter writer = new SimpleDataWriter();

mySerializerSerialize(addressInstance writer);

结束

强烈建议您亲自试用一下示例代码尤其是 SimpleSerialization 库我在 SimpleSerializer 一些有趣的部分都添加了注释希望能够有所帮助当然如果您需要在产品代码中进行严格的序列化那么确实要依靠 NET Framework 中提供的技术(例如 XmlSerializer)但如果您发现在运行时需要使用任意类型并能高效处理它们我希望您采用我的 SimpleSerialization 库作为自己的方案

[] [] [] []

               

上一篇:对.NET Framework 反射的反思[3]

下一篇:微软.Net程序设计FAQ