清晰
![](/icons/51746de.gif)
组件化目标是否因在库间共享过多类型信息而落空?或许您需要高效
![](/icons/51746de.gif)
强类型化数据存储
![](/icons/51746dou.gif)
但如果每次对象模型发展后都需要更新您
![](/icons/51746de.gif)
数据库架构
![](/icons/51746dou.gif)
那会耗费很大成本
![](/icons/51746dou.gif)
所以您更愿意在运行时推断出其类型架构吗?您需要交付能接受任意用户对象
![](/icons/51746de.gif)
组件
![](/icons/51746dou.gif)
并以某种智能化
![](/icons/51746de.gif)
方式处理它们吗?您希望库
![](/icons/51746de.gif)
调方者能以编程方式向您介绍说明它们
![](/icons/51746de.gif)
类型吗?
如果您发现自己在苦苦维持强类型化数据结构
![](/icons/51746de.gif)
同时
![](/icons/51746dou.gif)
又冀望于最大化运行时灵活性
![](/icons/51746dou.gif)
那么您大概会愿意考虑反射
![](/icons/51746dou.gif)
以及它如何改善您
![](/icons/51746de.gif)
软件Software
![](/icons/51746dou2.gif)
在本专栏中
![](/icons/51746dou.gif)
我将探讨 Microsoft? .NET Framework 中
![](/icons/51746System.gif)
.Reflection 命名空间
![](/icons/51746dou.gif)
以及它如何为您
![](/icons/51746de.gif)
开发体验提供助益
![](/icons/51746dou2.gif)
我将从
![](/icons/51746yi.gif)
些简单
![](/icons/51746de.gif)
举例开始
![](/icons/51746dou.gif)
最后将讲述如何处理现实世界中
![](/icons/51746de.gif)
序列化情形
![](/icons/51746dou2.gif)
在此过程中
![](/icons/51746dou.gif)
我会展示反射和 CodeDom 如何配合工作
![](/icons/51746dou.gif)
以有效处理运行时数据
![](/icons/51746dou2.gif)
在深入探究
![](/icons/51746System.gif)
.Reflection 的前
![](/icons/51746dou.gif)
我想先讨论
![](/icons/51746yi.gif)
下
![](/icons/51746yi.gif)
般
![](/icons/51746de.gif)
反射编程
![](/icons/51746dou2.gif)
首先
![](/icons/51746dou.gif)
反射可定义为由
![](/icons/51746yi.gif)
个编程系统提供
![](/icons/51746de.gif)
任何功能
![](/icons/51746dou.gif)
此功能使
![](/icons/51746chengxu.gif)
员可以在无需提前了解其标识或正式结构
![](/icons/51746de.gif)
情况下检查和操作代码实体
![](/icons/51746dou2.gif)
这部分内容很多
![](/icons/51746dou.gif)
我将逐
![](/icons/51746yi.gif)
展开介绍说明
![](/icons/51746dou2.gif)
首先
![](/icons/51746dou.gif)
反射提供了什么呢?您能用它做些什么呢?我倾向于将典型
![](/icons/51746de.gif)
以反射为中心
![](/icons/51746de.gif)
任务分为两类:检查和操作
![](/icons/51746dou2.gif)
检查需要分析对象和类型
![](/icons/51746dou.gif)
以收集有关其定义和行为
![](/icons/51746de.gif)
结构化信息
![](/icons/51746dou2.gif)
除了
![](/icons/51746yi.gif)
些基本规定的外
![](/icons/51746dou.gif)
通常这是在事先不了解它们
![](/icons/51746de.gif)
情况下进行
![](/icons/51746de.gif)
![](/icons/51746dou2.gif)
(例如
![](/icons/51746dou.gif)
在 .NET Framework 中
![](/icons/51746dou.gif)
任何东西都继承自
![](/icons/51746System.gif)
.Object
![](/icons/51746dou.gif)
并且
![](/icons/51746yi.gif)
个对象类型
![](/icons/51746de.gif)
引用通常是反射
![](/icons/51746de.gif)
![](/icons/51746yi.gif)
般起点
![](/icons/51746dou2.gif)
)
操作利用通过检查收集到
![](/icons/51746de.gif)
信息动态地
![](/icons/51746diaoyong.gif)
代码
![](/icons/51746dou.gif)
创建已发现类型
![](/icons/51746de.gif)
新例子
![](/icons/51746dou.gif)
或者甚至可以轻松地动态重新结构化类型和对象
![](/icons/51746dou2.gif)
需要指出
![](/icons/51746de.gif)
![](/icons/51746yi.gif)
个要点是
![](/icons/51746dou.gif)
对于大多数系统
![](/icons/51746dou.gif)
在运行时操作类型和对象
![](/icons/51746dou.gif)
较的在源代码中静态地进行同等操作
![](/icons/51746dou.gif)
会导致性能降低
![](/icons/51746dou2.gif)
由于反射
![](/icons/51746de.gif)
动态特性
![](/icons/51746dou.gif)
因此这是个必要
![](/icons/51746de.gif)
取舍
![](/icons/51746dou.gif)
不过有很多窍门技巧和最佳做法可以优化反射
![](/icons/51746de.gif)
性能(有关优化使用反射
![](/icons/51746de.gif)
更多深入信息
![](/icons/51746dou.gif)
请参见 msdn.microsoft.com/msdnmag/issues/05/07/Reflection)
![](/icons/51746dou2.gif)
那么
![](/icons/51746dou.gif)
什么是反射
![](/icons/51746de.gif)
目标呢?
![](/icons/51746chengxu.gif)
员实际检查和操作什么呢?在我对反射
![](/icons/51746de.gif)
定义中
![](/icons/51746dou.gif)
我用了“代码实体”这个新术语
![](/icons/51746dou.gif)
以强调
![](/icons/51746yi.gif)
个事实:从
![](/icons/51746chengxu.gif)
员
![](/icons/51746de.gif)
角度来说
![](/icons/51746dou.gif)
反射技术有时会使传统对象和类型的间
![](/icons/51746de.gif)
界限变得模糊
![](/icons/51746dou2.gif)
例如
![](/icons/51746dou.gif)
![](/icons/51746yi.gif)
个典型
![](/icons/51746de.gif)
以反射为中心
![](/icons/51746de.gif)
任务可能是:
从对象 O
![](/icons/51746de.gif)
句柄开始
![](/icons/51746dou.gif)
并使用反射获得其相关定义(类型 T)
![](/icons/51746de.gif)
句柄
检查类型 T
![](/icons/51746dou.gif)
获得它
![](/icons/51746de.gif)
思路方法 M
![](/icons/51746de.gif)
句柄
![](/icons/51746diaoyong.gif)
另
![](/icons/51746yi.gif)
个对象 O’(同样是类型 T)
![](/icons/51746de.gif)
思路方法 M
![](/icons/51746dou2.gif)
请注意
![](/icons/51746dou.gif)
我在从
![](/icons/51746yi.gif)
个例子穿梭到它
![](/icons/51746de.gif)
底层类型
![](/icons/51746dou.gif)
从这
![](/icons/51746yi.gif)
类型到
![](/icons/51746yi.gif)
个思路方法
![](/icons/51746dou.gif)
的后又使用此思路方法
![](/icons/51746de.gif)
句柄在另
![](/icons/51746yi.gif)
个例子上
![](/icons/51746diaoyong.gif)
它 — 显然这是在源代码中使用传统
![](/icons/51746de.gif)
C# 编程技术无法实现
![](/icons/51746de.gif)
![](/icons/51746dou2.gif)
在下文中探讨 .NET Framework
![](/icons/51746System.gif)
.Reflection 的后
![](/icons/51746dou.gif)
我会再次通过
![](/icons/51746yi.gif)
个具体
![](/icons/51746de.gif)
例子来解释这
![](/icons/51746yi.gif)
情形
![](/icons/51746dou2.gif)
某些编程语言本身可以通过语法提供反射
![](/icons/51746dou.gif)
而另
![](/icons/51746yi.gif)
些平台和框架(如 .NET Framework)则将其作为系统库
![](/icons/51746dou2.gif)
不管以何种方式提供反射
![](/icons/51746dou.gif)
在给定情形下使用反射技术
![](/icons/51746de.gif)
可能性相当复杂
![](/icons/51746dou2.gif)
编程系统提供反射
![](/icons/51746de.gif)
能力取决于诸多原因:
![](/icons/51746chengxu.gif)
员很好地利用了编程语言
![](/icons/51746de.gif)
功能表达了他
![](/icons/51746de.gif)
概念吗?编译器是否在输出中嵌入足够
![](/icons/51746de.gif)
结构化信息(元数据)
![](/icons/51746dou.gif)
以方便日后
![](/icons/51746de.gif)
解读?有没有
![](/icons/51746yi.gif)
个运行时子系统或主机解释器来消化这些元数据?平台库是否以对
![](/icons/51746chengxu.gif)
员有用
![](/icons/51746de.gif)
方式
![](/icons/51746dou.gif)
展示此解释结果?[Page]
如果您头脑中想象
![](/icons/51746de.gif)
是
![](/icons/51746yi.gif)
个复杂
![](/icons/51746de.gif)
、面向对象类型
![](/icons/51746de.gif)
系统
![](/icons/51746dou.gif)
但在代码中却表现为简单
![](/icons/51746de.gif)
、C 语言风格
![](/icons/51746de.gif)
![](/icons/51746hanshu.gif)
![](/icons/51746dou.gif)
而且没有正式
![](/icons/51746de.gif)
数据结构
![](/icons/51746dou.gif)
那么显然您
![](/icons/51746de.gif)
![](/icons/51746chengxu.gif)
不可能动态地推断出
![](/icons/51746dou.gif)
某变量 v1
![](/icons/51746de.gif)
指针指向某种类型 T
![](/icons/51746de.gif)
对象例子
![](/icons/51746dou2.gif)
![](/icons/51746yinwei.gif)
毕竟类型 T 是您头脑中
![](/icons/51746de.gif)
概念
![](/icons/51746dou.gif)
它从未在您
![](/icons/51746de.gif)
编程语句中明确地出现
![](/icons/51746dou2.gif)
但如果您使用
![](/icons/51746yi.gif)
种更为灵活
![](/icons/51746de.gif)
面向对象语言(如 C#)来表达
![](/icons/51746chengxu.gif)
![](/icons/51746de.gif)
抽象结构
![](/icons/51746dou.gif)
并直接引入类型 T
![](/icons/51746de.gif)
概念
![](/icons/51746dou.gif)
那么编译器就会把您
![](/icons/51746de.gif)
想法转换成某种日后可以通过合适
![](/icons/51746de.gif)
逻辑来理解
![](/icons/51746de.gif)
形式
![](/icons/51746dou.gif)
就象公共语言运行时 (CLR) 或某种动态语言解释器所提供
![](/icons/51746de.gif)
![](/icons/51746yi.gif)
样
![](/icons/51746dou2.gif)
反射完全是动态、运行时
![](/icons/51746de.gif)
技术吗?简单
![](/icons/51746de.gif)
说
![](/icons/51746dou.gif)
不是这样
![](/icons/51746dou2.gif)
整个开发和执行周期中
![](/icons/51746dou.gif)
很多时候反射对开发人员都可用且有用
![](/icons/51746dou2.gif)
![](/icons/51746yi.gif)
些编程语言通过独立编译器实现
![](/icons/51746dou.gif)
这些编译器将高级代码直接转换成机器能够识别
![](/icons/51746de.gif)
指令
![](/icons/51746dou2.gif)
输出文件只包括编译过
![](/icons/51746de.gif)
输入
![](/icons/51746dou.gif)
并且运行时没有用于接受不透明对象并动态分析其定义
![](/icons/51746de.gif)
支持逻辑
![](/icons/51746dou2.gif)
这正是许多传统 C 编译器
![](/icons/51746de.gif)
情形
![](/icons/51746dou2.gif)
![](/icons/51746yinwei.gif)
在目标可执行文件中几乎没有支持逻辑
![](/icons/51746dou.gif)
因此您无法完成太多动态反射
![](/icons/51746dou.gif)
然而编译器会不时提供静态反射 — 例如
![](/icons/51746dou.gif)
普遍运用
![](/icons/51746de.gif)
typeof 运算符允许
![](/icons/51746chengxu.gif)
员在编译时检查类型标识
![](/icons/51746dou2.gif)
另
![](/icons/51746yi.gif)
种完全区别
![](/icons/51746de.gif)
情况是
![](/icons/51746dou.gif)
解释性编程语言总是通过主进程获得执行(脚本语言通常属于此类)
![](/icons/51746dou2.gif)
由于
![](/icons/51746chengxu.gif)
![](/icons/51746de.gif)
完整定义是可用
![](/icons/51746de.gif)
(作为输入源代码)
![](/icons/51746dou.gif)
并跟完整
![](/icons/51746de.gif)
语言实现结合在
![](/icons/51746yi.gif)
起(作为解释器本身)
![](/icons/51746dou.gif)
因此所有支持自我分析所需
![](/icons/51746de.gif)
技术都到位了
![](/icons/51746dou2.gif)
这种动态语言频繁地提供全面反射功能
![](/icons/51746dou.gif)
以及
![](/icons/51746yi.gif)
组用于动态分析和操作
![](/icons/51746chengxu.gif)
![](/icons/51746de.gif)
丰富工具
![](/icons/51746dou2.gif)
.NET Framework CLR 和它
![](/icons/51746de.gif)
承载语言如 C# 属于中间形态
![](/icons/51746dou2.gif)
编译器用来把源代码转换成 IL 和元数据
![](/icons/51746dou.gif)
后者和源代码相比虽属于较低级别或者较低“逻辑性”
![](/icons/51746dou.gif)
但仍然保留了很多抽象结构和类型信息
![](/icons/51746dou2.gif)
![](/icons/51746yi.gif)
旦 CLR 启动和承载了此
![](/icons/51746chengxu.gif)
![](/icons/51746dou.gif)
基类库 (BCL)
![](/icons/51746System.gif)
.Reflection 库便可以使用此信息
![](/icons/51746dou.gif)
并返回有关对象类型、类型成员、成员签名等
![](/icons/51746de.gif)
信息
![](/icons/51746dou2.gif)
此外
![](/icons/51746dou.gif)
它也可以支持
![](/icons/51746diaoyong.gif)
![](/icons/51746dou.gif)
包括后期绑定
![](/icons/51746diaoyong.gif)
![](/icons/51746dou2.gif)
.NET 中
![](/icons/51746de.gif)
反射
要在用 .NET Framework 编程时利用反射
![](/icons/51746dou.gif)
您可以使用
![](/icons/51746System.gif)
.Reflection 命名空间
![](/icons/51746dou2.gif)
此命名空间提供封装了很多运行时概念
![](/icons/51746de.gif)
类
![](/icons/51746dou.gif)
例如
![](/icons/51746chengxu.gif)
集、模块、类型、思路方法、构造
![](/icons/51746hanshu.gif)
、字段和属性
![](/icons/51746dou2.gif)
图 1 中
![](/icons/51746de.gif)
表显示
![](/icons/51746dou.gif)
![](/icons/51746System.gif)
.Reflection 中
![](/icons/51746de.gif)
类如何和概念上运行时
![](/icons/51746de.gif)
对应项对应起来
![](/icons/51746dou2.gif)
尽管很重要
![](/icons/51746dou.gif)
不过
![](/icons/51746System.gif)
.Reflection.Assembly 和
![](/icons/51746System.gif)
.Reflection.Module 主要用于定位新代码并将其加载到运行时
![](/icons/51746dou2.gif)
本专栏中
![](/icons/51746dou.gif)
我暂不讨论这些部分
![](/icons/51746dou.gif)
并且假定所有相关代码都已经加载
![](/icons/51746dou2.gif)
要检查和操作已加载代码
![](/icons/51746dou.gif)
典型模式主要是
![](/icons/51746System.gif)
.Type
![](/icons/51746dou2.gif)
通常
![](/icons/51746dou.gif)
您从获得
![](/icons/51746yi.gif)
个所关注运行时类别
![](/icons/51746System.gif)
.Type 例子开始(通过 Object.GetType)
![](/icons/51746dou2.gif)
接着您可以使用
![](/icons/51746System.gif)
.Type
![](/icons/51746de.gif)
各种思路方法
![](/icons/51746dou.gif)
在
![](/icons/51746System.gif)
.Reflection 中探索类型
![](/icons/51746de.gif)
定义并获得其它类
![](/icons/51746de.gif)
例子
![](/icons/51746dou2.gif)
例如
![](/icons/51746dou.gif)
如果您对某特定思路方法感兴趣
![](/icons/51746dou.gif)
并希望获得此思路方法
![](/icons/51746de.gif)
![](/icons/51746yi.gif)
个
![](/icons/51746System.gif)
.Reflection.MethodInfo 例子(可能通过 Type.GetMethod)
![](/icons/51746dou2.gif)
同样
![](/icons/51746dou.gif)
如果您对某字段感兴趣
![](/icons/51746dou.gif)
并希望获得此字段
![](/icons/51746de.gif)
![](/icons/51746yi.gif)
个
![](/icons/51746System.gif)
.Reflection.FieldInfo 例子(可能通过 Type.GetField)
![](/icons/51746dou2.gif)
[Page]
![](/icons/51746yi.gif)
旦获得所有必要
![](/icons/51746de.gif)
反射例子对象
![](/icons/51746dou.gif)
即可根据需要遵循检查或操作
![](/icons/51746de.gif)
步骤继续
![](/icons/51746dou2.gif)
检查时
![](/icons/51746dou.gif)
您在反射类中使用各种描述性属性
![](/icons/51746dou.gif)
获得您需要
![](/icons/51746de.gif)
信息(这是通用类型吗?这是例子思路方法吗?)
![](/icons/51746dou2.gif)
操作时
![](/icons/51746dou.gif)
您可以动态地
![](/icons/51746diaoyong.gif)
并执行思路方法
![](/icons/51746dou.gif)
通过
![](/icons/51746diaoyong.gif)
构造
![](/icons/51746hanshu.gif)
创建新对象
![](/icons/51746dou.gif)
等等
![](/icons/51746dou2.gif)
检查类型和成员
让我们跳转到
![](/icons/51746yi.gif)
些代码中
![](/icons/51746dou.gif)
探索如何运用基本反射进行检查
![](/icons/51746dou2.gif)
我将集中讨论类型分析
![](/icons/51746dou2.gif)
从
![](/icons/51746yi.gif)
个对象开始
![](/icons/51746dou.gif)
我将检索它
![](/icons/51746de.gif)
类型
![](/icons/51746dou.gif)
而后考察几个有意思
![](/icons/51746de.gif)
成员(请参见图 2)
![](/icons/51746dou2.gif)
首先需要注意
![](/icons/51746de.gif)
是
![](/icons/51746dou.gif)
在类定义中
![](/icons/51746dou.gif)
乍看起来介绍说明思路方法
![](/icons/51746de.gif)
篇幅比我预期
![](/icons/51746de.gif)
要多很多
![](/icons/51746dou2.gif)
这些额外
![](/icons/51746de.gif)
思路方法是从哪里来
![](/icons/51746de.gif)
呢?任何精通 .NET Framework 对象层次结构
![](/icons/51746de.gif)
人
![](/icons/51746dou.gif)
都会识别从通用基类 Object 自身继承
![](/icons/51746de.gif)
这些思路方法
![](/icons/51746dou2.gif)
(事实上
![](/icons/51746dou.gif)
我首先使用了 Object.GetType 检索其类型
![](/icons/51746dou2.gif)
)此外
![](/icons/51746dou.gif)
您可以看到属性
![](/icons/51746de.gif)
getter
![](/icons/51746hanshu.gif)
![](/icons/51746dou2.gif)
现在
![](/icons/51746dou.gif)
如果您只需要 MyClass 自身显式定义
![](/icons/51746de.gif)
![](/icons/51746hanshu.gif)
![](/icons/51746dou.gif)
该如何办呢?换句话说
![](/icons/51746dou.gif)
您如何隐藏继承
![](/icons/51746de.gif)
![](/icons/51746hanshu.gif)
?或者您可能只需要显式定义
![](/icons/51746de.gif)
例子
![](/icons/51746hanshu.gif)
?
随便在线看看 MSDN?
![](/icons/51746dou.gif)
就会发现大家都愿意使用 GetMethods 第 2个重载思路方法
![](/icons/51746dou.gif)
它接受 BindingFlags 参数
![](/icons/51746dou2.gif)
通过结合来自 BindingFlags 枚举中区别
![](/icons/51746de.gif)
值
![](/icons/51746dou.gif)
您可以让
![](/icons/51746hanshu.gif)
仅返回所需
![](/icons/51746de.gif)
思路方法子集
![](/icons/51746dou2.gif)
替换 GetMethods
![](/icons/51746diaoyong.gif)
![](/icons/51746dou.gif)
代的以:
GetMethods(BindingFlags.Instance | BindingFlags.DeclaredOnly |
BindingFlags.Public)
结果是
![](/icons/51746dou.gif)
您得到以下输出(注意这里不存在静态帮助器
![](/icons/51746hanshu.gif)
和继承自
![](/icons/51746System.gif)
.Object
![](/icons/51746de.gif)
![](/icons/51746hanshu.gif)
)
![](/icons/51746dou2.gif)
Reflection Demo Example 1
Type Name: MyClass
Method Name: MyMethod1
Method Name: MyMethod2
Method Name: get_MyProperty
Property Name: MyProperty
如果您事先知道类型名称(完全限定)和成员
![](/icons/51746dou.gif)
又该如何?您如何完成从枚举类型向检索类型
![](/icons/51746de.gif)
转换?有了前两个举例中
![](/icons/51746de.gif)
代码
![](/icons/51746dou.gif)
您已经有了能够实现基元类浏览器
![](/icons/51746de.gif)
基本组件
![](/icons/51746dou2.gif)
通过名称您可以找到
![](/icons/51746yi.gif)
个运行时实体
![](/icons/51746dou.gif)
然后枚举其各种相关属性
![](/icons/51746dou2.gif)
动态
![](/icons/51746diaoyong.gif)
代码
迄今为止
![](/icons/51746dou.gif)
我已经获得运行时对象
![](/icons/51746de.gif)
句柄(如类型和思路方法)
![](/icons/51746dou.gif)
仅作描述用
![](/icons/51746dou.gif)
例如输出它们
![](/icons/51746de.gif)
名称
![](/icons/51746dou2.gif)
但是如何做得更多呢?如何实际
![](/icons/51746diaoyong.gif)
某个思路方法呢?
此例
![](/icons/51746de.gif)
几个要点是:首先
![](/icons/51746dou.gif)
从
![](/icons/51746yi.gif)
个 MyClass, mc1 例子检索
![](/icons/51746yi.gif)
个
![](/icons/51746System.gif)
.Type 例子
![](/icons/51746dou.gif)
然后
![](/icons/51746dou.gif)
从该类型检索
![](/icons/51746yi.gif)
个 MethodInfo 例子
![](/icons/51746dou2.gif)
最后
![](/icons/51746dou.gif)
当
![](/icons/51746diaoyong.gif)
MethodInfo 时
![](/icons/51746dou.gif)
通过把它作为
![](/icons/51746diaoyong.gif)
![](/icons/51746de.gif)
第
![](/icons/51746yi.gif)
个参数来传递
![](/icons/51746dou.gif)
将其绑定到另
![](/icons/51746yi.gif)
个 MyClass (mc2) 例子中
![](/icons/51746dou2.gif)
前面讲过
![](/icons/51746dou.gif)
对于您预期在源代码中见到
![](/icons/51746de.gif)
类型和对象使用的间
![](/icons/51746de.gif)
区别
![](/icons/51746dou.gif)
这个举例使这种区别变得模糊
![](/icons/51746dou2.gif)
逻辑上
![](/icons/51746dou.gif)
您检索了
![](/icons/51746yi.gif)
个思路方法
![](/icons/51746de.gif)
句柄
![](/icons/51746dou.gif)
然后
![](/icons/51746diaoyong.gif)
该思路方法
![](/icons/51746dou.gif)
就象它属于
![](/icons/51746yi.gif)
个区别
![](/icons/51746de.gif)
对象
![](/icons/51746yi.gif)
样
![](/icons/51746dou2.gif)
对于熟悉
![](/icons/51746hanshu.gif)
式编程语言
![](/icons/51746de.gif)
![](/icons/51746chengxu.gif)
员来说
![](/icons/51746dou.gif)
这可能轻而易举;但对于只熟悉 C#
![](/icons/51746de.gif)
![](/icons/51746chengxu.gif)
员来说
![](/icons/51746dou.gif)
要分离对象实现和对象例子化
![](/icons/51746dou.gif)
可能就不是那么直观了
![](/icons/51746dou2.gif)
组合在
![](/icons/51746yi.gif)
起
至此我已经探讨过检查和
![](/icons/51746diaoyong.gif)
![](/icons/51746de.gif)
基本原理
![](/icons/51746dou.gif)
接下来我会用具体
![](/icons/51746de.gif)
例子把它们组合在
![](/icons/51746yi.gif)
起
![](/icons/51746dou2.gif)
设想您希望交付
![](/icons/51746yi.gif)
个库
![](/icons/51746dou.gif)
带有必须处理对象
![](/icons/51746de.gif)
静态帮助器
![](/icons/51746hanshu.gif)
![](/icons/51746dou2.gif)
但在设计
![](/icons/51746de.gif)
时候
![](/icons/51746dou.gif)
您对这些对象
![](/icons/51746de.gif)
类型没有任何概念!这要看
![](/icons/51746hanshu.gif)
![](/icons/51746diaoyong.gif)
方
![](/icons/51746de.gif)
指示
![](/icons/51746dou.gif)
看他希望如何从这些对象中提取有意义
![](/icons/51746de.gif)
信息
![](/icons/51746dou2.gif)
![](/icons/51746hanshu.gif)
将接受
![](/icons/51746yi.gif)
个对象集合
![](/icons/51746dou.gif)
和
![](/icons/51746yi.gif)
个思路方法
![](/icons/51746de.gif)
![](/icons/51746zifu.gif)
串描述符
![](/icons/51746dou2.gif)
然后它将遍历该集合
![](/icons/51746dou.gif)
![](/icons/51746diaoyong.gif)
每个对象
![](/icons/51746de.gif)
思路方法
![](/icons/51746dou.gif)
用
![](/icons/51746yi.gif)
些
![](/icons/51746hanshu.gif)
聚合返回值(请参见图 5)
![](/icons/51746dou2.gif)
[Page]
就此例而言
![](/icons/51746dou.gif)
我要声明
![](/icons/51746yi.gif)
些约束条件
![](/icons/51746dou2.gif)
首先
![](/icons/51746dou.gif)
![](/icons/51746zifu.gif)
串参数描述
![](/icons/51746de.gif)
思路方法(必须由每个对象
![](/icons/51746de.gif)
底层类型实现)不会接受任何参数
![](/icons/51746dou.gif)
并将返回
![](/icons/51746yi.gif)
个整数
![](/icons/51746dou2.gif)
代码将遍历对象集合
![](/icons/51746dou.gif)
![](/icons/51746diaoyong.gif)
指定
![](/icons/51746de.gif)
思路方法
![](/icons/51746dou.gif)
逐步计算出所有值
![](/icons/51746de.gif)
平均值
![](/icons/51746dou2.gif)
最后
![](/icons/51746dou.gif)
![](/icons/51746yinwei.gif)
这不是生产代码
![](/icons/51746dou.gif)
在求和
![](/icons/51746de.gif)
时候我不用担心参数验证或整数溢出
![](/icons/51746dou2.gif)
在浏览举例代码时
![](/icons/51746dou.gif)
可以看到主
![](/icons/51746hanshu.gif)
和静态帮助器 ComputeAverage 的间
![](/icons/51746de.gif)
协议除了对象自身
![](/icons/51746de.gif)
通用基类的外
![](/icons/51746dou.gif)
并不依赖任何类型信息
![](/icons/51746dou2.gif)
换句话说
![](/icons/51746dou.gif)
您可以彻底改变正在传送
![](/icons/51746de.gif)
对象
![](/icons/51746de.gif)
类型和结构
![](/icons/51746dou.gif)
但只要总是能使用
![](/icons/51746zifu.gif)
串描述
![](/icons/51746yi.gif)
个思路方法
![](/icons/51746dou.gif)
且该思路方法返回整数
![](/icons/51746dou.gif)
ComputeAverage 就可以正常工作!
需要注意
![](/icons/51746de.gif)
![](/icons/51746yi.gif)
个关键问题跟隐藏在最后这个例子中
![](/icons/51746de.gif)
MethodInfo(
![](/icons/51746yi.gif)
般反射)有关
![](/icons/51746dou2.gif)
注意
![](/icons/51746dou.gif)
在 ComputeAverage
![](/icons/51746de.gif)
foreach 循环中
![](/icons/51746dou.gif)
代码只从集合中
![](/icons/51746de.gif)
第
![](/icons/51746yi.gif)
个对象中抓取
![](/icons/51746yi.gif)
个 MethodInfo
![](/icons/51746dou.gif)
然后绑定用于所有后续对象
![](/icons/51746de.gif)
![](/icons/51746diaoyong.gif)
![](/icons/51746dou2.gif)
正如编码所示
![](/icons/51746dou.gif)
它运行良好 — 这是 MethodInfo 缓存Cache
![](/icons/51746de.gif)
![](/icons/51746yi.gif)
个简单例子
![](/icons/51746dou2.gif)
但此处有
![](/icons/51746yi.gif)
个根本性
![](/icons/51746de.gif)
局限
![](/icons/51746dou2.gif)
MethodInfo 例子仅能由其检索对象同等层级类型
![](/icons/51746de.gif)
例子
![](/icons/51746diaoyong.gif)
![](/icons/51746dou2.gif)
![](/icons/51746yinwei.gif)
传入了 IntReturner 和 SonOfIntReturner(继承自 IntReturner)
![](/icons/51746de.gif)
例子
![](/icons/51746dou.gif)
才能这样运行
![](/icons/51746dou2.gif)
在举例代码中
![](/icons/51746dou.gif)
已经包含了名为 EnemyOfIntReturner
![](/icons/51746de.gif)
类
![](/icons/51746dou.gif)
它实现了和其他两个类相同
![](/icons/51746de.gif)
基本协议
![](/icons/51746dou.gif)
但并没有共享任何常见共享类型
![](/icons/51746dou2.gif)
换句话说
![](/icons/51746dou.gif)
该接口逻辑上等同
![](/icons/51746dou.gif)
但在类型层级上没有重叠
![](/icons/51746dou2.gif)
要探讨 MethodInfo 在该情形下
![](/icons/51746de.gif)
使用
![](/icons/51746dou.gif)
请尝试向集合添加其他对象
![](/icons/51746dou.gif)
通过“
![](/icons/51746new.gif)
EnemyOfIntReturner(10)”得到
![](/icons/51746yi.gif)
个例子
![](/icons/51746dou.gif)
再次运行举例
![](/icons/51746dou2.gif)
您会遇到
![](/icons/51746yi.gif)
个异常
![](/icons/51746dou.gif)
指出 MethodInfo 不能用于
![](/icons/51746diaoyong.gif)
指定
![](/icons/51746de.gif)
对象
![](/icons/51746dou.gif)
![](/icons/51746yinwei.gif)
它和获得 MethodInfo 时
![](/icons/51746de.gif)
原始类型完全无关(即使思路方法名称和基本协议是等同
![](/icons/51746de.gif)
)
![](/icons/51746dou2.gif)
要使您
![](/icons/51746de.gif)
代码达到生产水准
![](/icons/51746dou.gif)
您需要做好遇到这
![](/icons/51746yi.gif)
情形
![](/icons/51746de.gif)
准备
![](/icons/51746yi.gif)
个可能
![](/icons/51746de.gif)
解决方案可以是通过自己分析所有传入对象
![](/icons/51746de.gif)
类型
![](/icons/51746dou.gif)
保留对其共享
![](/icons/51746de.gif)
类型层级(如果有)
![](/icons/51746de.gif)
解释
![](/icons/51746dou2.gif)
如果下
![](/icons/51746yi.gif)
对象
![](/icons/51746de.gif)
类型和任意已知类型层级相异
![](/icons/51746dou.gif)
就需要获取和存储
![](/icons/51746yi.gif)
个新
![](/icons/51746de.gif)
MethodInfo
![](/icons/51746dou2.gif)
另
![](/icons/51746yi.gif)
解决方案是捕获 TargetException
![](/icons/51746dou.gif)
并重新获取
![](/icons/51746yi.gif)
个 MethodInfo 例子
![](/icons/51746dou2.gif)
这里提到
![](/icons/51746de.gif)
两种解决方案都各有其优缺点
![](/icons/51746dou2.gif)
Joel Pobar 为本杂志 2007 5月期写过
![](/icons/51746yi.gif)
篇优秀
![](/icons/51746de.gif)
文章
![](/icons/51746dou.gif)
内容有关 MethodInfo 缓冲和我所极力推荐
![](/icons/51746de.gif)
反射性能
![](/icons/51746dou2.gif)
希望此举例演示
![](/icons/51746de.gif)
向应用
![](/icons/51746chengxu.gif)
或框架中添加反射
![](/icons/51746dou.gif)
可以为日后
![](/icons/51746de.gif)
自定义或可扩展性增加更多
![](/icons/51746de.gif)
灵活性
![](/icons/51746dou2.gif)
不可否认
![](/icons/51746dou.gif)
较的本机编程语言中
![](/icons/51746de.gif)
同等逻辑
![](/icons/51746dou.gif)
使用反射可能会有些繁琐
![](/icons/51746dou2.gif)
如果您感到对您或您
![](/icons/51746de.gif)
客户来说
![](/icons/51746dou.gif)
向代码中添加基于反射
![](/icons/51746de.gif)
后期绑定过于麻烦(毕竟他们需要以某种方式在您
![](/icons/51746de.gif)
框架中介绍说明他们
![](/icons/51746de.gif)
类型和代码)
![](/icons/51746dou.gif)
那么可能仅需要适度
![](/icons/51746de.gif)
灵活性以取得某种平衡
![](/icons/51746dou2.gif)
序列化
![](/icons/51746de.gif)
高效类型处理
至此我们已通过若干举例讲述了 .NET 反射
![](/icons/51746de.gif)
基本原理
![](/icons/51746dou.gif)
接下来让我们看
![](/icons/51746yi.gif)
下现实世界中
![](/icons/51746de.gif)
情形
![](/icons/51746dou2.gif)
如果您
![](/icons/51746de.gif)
软件Software通过 Web 服务或其他进程外远程技术和其他系统进行交互
![](/icons/51746dou.gif)
那么您很可能已经遇到序列化问题
![](/icons/51746dou2.gif)
序列化本质上是将活动
![](/icons/51746de.gif)
、占用内存
![](/icons/51746de.gif)
对象
![](/icons/51746dou.gif)
转变成适合线上传输或磁盘存储
![](/icons/51746de.gif)
数据格式
.NET Framework 中
![](/icons/51746System.gif)
.Xml.Serialization 命名空间提供了拥有 XmlSerializer
![](/icons/51746de.gif)
强大序列化引擎
![](/icons/51746dou.gif)
它可以使用任意托管对象
![](/icons/51746dou.gif)
并将其转换成 XML(日后也可将 XML 数据转换回类型化
![](/icons/51746de.gif)
对象例子
![](/icons/51746dou.gif)
这
![](/icons/51746yi.gif)
过程称的为反序列化)
![](/icons/51746dou2.gif)
XmlSerializer 类是
![](/icons/51746yi.gif)
种强大
![](/icons/51746de.gif)
、企业就绪
![](/icons/51746de.gif)
软件Software片断
![](/icons/51746dou.gif)
如果您在项目中面临序列化问题
![](/icons/51746dou.gif)
它将是您
![](/icons/51746de.gif)
首选
![](/icons/51746dou2.gif)
但为了教学目
![](/icons/51746de.gif)
![](/icons/51746dou.gif)
我们来探讨如何实现序列化(或者其他类似
![](/icons/51746de.gif)
运行时类型处理例子)
![](/icons/51746dou2.gif)
[Page]
设想情形:您正在交付
![](/icons/51746yi.gif)
个框架
![](/icons/51746dou.gif)
需要使用任意用户类型
![](/icons/51746de.gif)
对象例子
![](/icons/51746dou.gif)
并将其转换成某种智能型数据格式
![](/icons/51746dou2.gif)
例如
![](/icons/51746dou.gif)
假定有
![](/icons/51746yi.gif)
个驻留内存
![](/icons/51746de.gif)
对象
![](/icons/51746dou.gif)
类型为如下所示
![](/icons/51746de.gif)
Address:
(pseudocode)
![](/icons/51746class.gif)
Address
{
AddressID id;
String Street, City;
StateType State;
ZipCodeType ZipCode;
}
如何生成适当
![](/icons/51746de.gif)
数据表示形式以方便日后使用?或许
![](/icons/51746yi.gif)
个简单
![](/icons/51746de.gif)
文本呈现将解决这
![](/icons/51746yi.gif)
问题:
Address: 123
Street: 1 Microsoft Way
City: Redmond
State: WA
Zip: 98052
如果事先完全了解需要转换
![](/icons/51746de.gif)
正式数据类型(例如自己编写代码时)
![](/icons/51746dou.gif)
事情就变得非常简单:
foreach(Address a in AddressList)
{
Console.WriteLine(“Address:{0}”, a.ID);
Console.WriteLine(“\\tStreet:{0}”, a.Street);
... // and so _disibledevent=>SimpleDataWriter writer =
![](/icons/51746new.gif)
SimpleDataWriter
![](/icons/51746kh.gif)
;
mySerializer.Serialize(addressInstance, writer);
结束
强烈建议您亲自试用
![](/icons/51746yi.gif)
下举例代码
![](/icons/51746dou.gif)
尤其是 SimpleSerialization 库
![](/icons/51746dou2.gif)
我在 SimpleSerializer
![](/icons/51746yi.gif)
些有趣
![](/icons/51746de.gif)
部分都添加了注释
![](/icons/51746dou.gif)
希望能够有所帮助
![](/icons/51746dou2.gif)
当然
![](/icons/51746dou.gif)
如果您需要在产品代码中进行严格
![](/icons/51746de.gif)
序列化
![](/icons/51746dou.gif)
那么确实要依靠 .NET Framework 中提供
![](/icons/51746de.gif)
技术(例如 XmlSerializer)
![](/icons/51746dou2.gif)
但如果您发现在运行时需要使用任意类型并能高效处理它们
![](/icons/51746dou.gif)
我希望您采用我
![](/icons/51746de.gif)
SimpleSerialization 库作为自己
![](/icons/51746de.gif)
方案