.Net开发笔记(二十一) 反射在.net中的应用

简介:

反射概念在网上到处都有,但是讲到的具体的应用很少,一个重要的原因是现实中真的很少用得到它。引用msdn上对“反射”的解释:

"通过 System.Reflection 命名空间中的类以及 System.Type,您可以获取有关已加载的程序集和在其中定义的类型(如类、接口和值类型)的信息。 您也可以使用反射在运行时创建类型实例,以及调用和访问这些实例。"

这个解释着实让人难以理解,至少对新手来讲,一头雾水。那么这篇文章我首先从概念下手,用一种尽量易于理解的方式解释一下反射到底是个什么东西。文章最后附加一个“反射”应用的demo,它能监听任何一个程序集中的任何一个Control(深度优先顺序遍历所有子控件)的所有事件信息。

在程序开发阶段,如果我们要使用一个类型(包括实例化该类型对象,访问对象等等操作),分三个步骤:

  • 添加包含了这个类型程序集的引用(.net自带的类型程序集默认已引用);
  • 代码中直接使用该类型(用一种文本字符的形式,比如类型名、方法名、属性名);
  • 编译正确通过,程序运行。

图1

以上是我们常用的开发步骤,几乎不用去想为什么要这样,每个人都会。这个流程中第一个前提就是“要引用包含了这个类型的程序集”。假设某一次开发过程中,我们不能提前引用到包含这个类型的程序集(先不要否定这种情况,只能说明你没碰到),那么我们改怎么写代码?正常情况下,我们访问A类是这样的(假设A类在A.dll程序集中):

  View Code

正常编译通过。但是现在我们没有引用A.dll,我们改怎么写代码?还是像上面那样写吗?不对,因为编译通不过,编译器会提示“缺少对程序集的引用”(这个很容易理解,因为你没有引用程序集,编译器肯定不会知道)。

以上就是我们会碰到的一种情况,即:

在有些时候,我们可能会使用一种数据类型,但是开发阶段并不能引用到包含该类型的程序集,包含了这个类型的程序集只能在程序运行起来之后,动态的引用进来。开发阶段引用程序集如果叫“静态引用程序集”,那么运行时引用程序集就应该叫“动态引用程序集”了。后者会造成一个问题:我们该怎么写代码去访问动态引用程序集中的类型

图2

这个时候,反射的作用就出来了。反射能够让我们使用在编译阶段编译器不知道的数据类型(注意是编译器不知道,不是我们不知道)。再举前面使用A类型的例子,我们在开发阶段没有引用A.dll程序集,因此下面的代码无法通过编译:

  View Code

 但是,我们知道程序运行之后,可以动态引用到A.dll,那么现在代码中怎么使用A类型呢?看下面的代码:

  View Code

上面代码能够通过编译,我们可以通过以上代码去访问A.dll程序集中的A类型,即使在开发阶段我们没有A.dll的引用。需要注意的几点有:

1)虽然我们在开发阶段不能引用到A.dll程序集,但是我们应该对A.dll中的类型有了解,知道命名空间,知道数据类型名称,知道方法名称参数类型,知道事件名称委托类型等等,也就是说,虽然编译器不知道A.dll中的类型信息,我们开发人员必须知道A.dll中的类型信息,这样以来,我们才能利用“反射”加上“文本字符”作为标示去访问这个类型。

2)1)中规定的开发人员必须了解A.dll中的类型信息,仅仅是当你需要详细的使用一个类型对象时,如果你只需要获取A.dll中的有哪些类型、每个类型有哪些方法参数属性事件等,然后将他们的信息显示出来,完全没必要知道A.dll中的类型信息,比如VS中编辑器的智能提示功能,或者Reflector等利用反射实现数据集中类型信息显示的软件,它们的开发人员知道你的程序集信息吗?不知道,但是还是能工作很好。但是就上面“使用A类型”的例子来讲,你必须知道A.dll中的A类型中有个叫EventName的事件,你才能给它的对象注册事件,否则可以说你根本使用不了A类型的对象。

3)编译阶段,对象和方法就可以关联起来(比如a.DoSomething()能通过编译),这种如果称之为“早期绑定”(early binding),那么通过反射将对象和方法关联起来就称为“晚期绑定”(late binding)。前者在编译阶段编译器可以检查正确性,后者编译器无能为力,因为编译器不知道A.dll的任何信息。

一张图区分两种访问程序集中类型的区别:

图3

个人认为,正常开发中用不到反射,所以尽量避免使用反射(反射有缺陷,运行性能编译阶段不能检查正确性等),本系列博客(十七)中讲到的扩展应用程序,就使用到了反射,文中指出将插件打包成dll程序集后,放入宿主程序的plugins目录中,宿主程序启动后,会动态引用plugins目录中的程序集,动态创建插件类型实例,然后访问它。那么如果你是宿主程序的开发人员,你会在开发阶段引用到第三方开发的插件程序集dll文件吗?不能,但是你还是得在代码中使用它的类型。

注:上面扩展应用程序中不全使用反射去访问动态引用程序集中的类型,因为它使用到了一个IPlugin的接口,动态实例化插件对象后,是使用IPlugin接口引用这个对象,之后所有的都是通过这个接口去访问对象(之后没有使用到反射),它避免了使用反射的性能问题和在编译阶段能够检查程序的正确性(开发阶段宿主程序能够引用IPlugin接口程序集),这个也是必须使用反射场合的一种改进,后续有机会我会详细说明。

另外网上有很多讲述反射的文章,都是用类似如下代码作为反射应用实例,

  View Code

以上类似代码并没有错误,只是我觉得会给人误导,反射的真正使用场合不在这里(这里完全用不着,为什么不直接使用btn1.Text=”123”呢?),看多了,人们就会认为反射就是这作用,用在这里。

Demo中包含了两个项目,一个是简单的说明了正常方法使用BackgroundWorker这个类型,和动态引用程序集动态创建BackgroundWorker类型对象(假装开发阶段没有引用包含BackgroundWorker类型的程序集),两者的区别。另一个项目能够动态引用程序集,并且动态实例化Control类实例,关键还能监听任何控件的所有事件,然后输出事件信息,这个有点复杂,不仅仅使用到了System.Reflection命名空间中的类型,还用了System.Reflection.Emit命名空间中的类型,后者可以动态创建类型,由于每个控件的每个事件类型不一样,并且个数还不确定,所以我们没有办法事先定义一个通用的事件注册者,只能挨个为每个事件动态创建一个事件注册者类。第二个项目流程见下图:

图4

第二个项目参见了CodeProject上老外的一篇文章(http://www.codeproject.com/Articles/3317/ControlInspector-monitor-Windows-Forms-events-as-t),注释请参见我的,代码中有详细的中文解释。

Demo截图:

图5 静态引用程序集访问类型 和 动态引用程序集访问类型的区别

图6 反射应用

总之,反射能够让你使用在编译阶段还不可达的程序集(类型)。

源码下载地址:http://files.cnblogs.com/xiaozhi_5638/ReflectionTest.rar

 

希望有帮助!

作者:周见智 
出处:http://www.cnblogs.com/xiaozhi_5638/ 
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

分类:  .NET Framework
标签:  c#

本文转自周见智博客博客园博客,原文链接:http://www.cnblogs.com/xiaozhi_5638/p/3492668.html,如需转载请自行联系原作者
目录
相关文章
|
12天前
|
存储 Shell Linux
快速上手基于 BaGet 的脚本自动化构建 .net 应用打包
本文介绍了如何使用脚本自动化构建 `.net` 应用的 `nuget` 包并推送到指定服务仓库。首先概述了 `BaGet`——一个开源、轻量级且高性能的 `NuGet` 服务器,支持多种存储后端及配置选项。接着详细描述了 `BaGet` 的安装、配置及使用方法,并提供了 `PowerShell` 和 `Bash` 脚本实例,用于自动化推送 `.nupkg` 文件。最后总结了 `BaGet` 的优势及其在实际部署中的便捷性。
45 10
|
11天前
|
C#
在.NET Core中灵活使用反射
在.NET Core中灵活使用反射
|
11天前
|
存储 运维
.NET开发必备技巧:使用Visual Studio分析.NET Dump,快速查找程序内存泄漏问题!
.NET开发必备技巧:使用Visual Studio分析.NET Dump,快速查找程序内存泄漏问题!
|
11天前
|
SQL 关系型数据库 数据库
七天.NET 8操作SQLite入门到实战详细教程(选型、开发、发布、部署)
七天.NET 8操作SQLite入门到实战详细教程(选型、开发、发布、部署)
|
11天前
|
消息中间件 开发框架 前端开发
YuebonCore:基于.NET8开源、免费的权限管理及快速开发框架
YuebonCore:基于.NET8开源、免费的权限管理及快速开发框架
|
16天前
|
开发框架 JavaScript 前端开发
|
1天前
|
数据采集 JSON API
.NET 3.5 中 HttpWebRequest 的核心用法及应用
【9月更文挑战第7天】在.NET 3.5环境下,HttpWebRequest 类是处理HTTP请求的一个核心组件,它封装了HTTP协议的细节,使得开发者可以方便地发送HTTP请求并接收响应。本文将详细介绍HttpWebRequest的核心用法及其实战应用。
16 6
|
18天前
|
数据库 C# 开发者
WPF开发者必读:揭秘ADO.NET与Entity Framework数据库交互秘籍,轻松实现企业级应用!
【8月更文挑战第31天】在现代软件开发中,WPF 与数据库的交互对于构建企业级应用至关重要。本文介绍了如何利用 ADO.NET 和 Entity Framework 在 WPF 应用中访问和操作数据库。ADO.NET 是 .NET Framework 中用于访问各类数据库(如 SQL Server、MySQL 等)的类库;Entity Framework 则是一种 ORM 框架,支持面向对象的数据操作。文章通过示例展示了如何在 WPF 应用中集成这两种技术,提高开发效率。
34 0
|
18天前
|
C# Windows 开发者
超越选择焦虑:深入解析WinForms、WPF与UWP——谁才是打造顶级.NET桌面应用的终极利器?从开发效率到视觉享受,全面解读三大框架优劣,助你精准匹配项目需求,构建完美桌面应用生态系统
【8月更文挑战第31天】.NET框架为开发者提供了多种桌面应用开发选项,包括WinForms、WPF和UWP。WinForms简单易用,适合快速开发基本应用;WPF提供强大的UI设计工具和丰富的视觉体验,支持XAML,易于实现复杂布局;UWP专为Windows 10设计,支持多设备,充分利用现代硬件特性。本文通过示例代码详细介绍这三种框架的特点,帮助读者根据项目需求做出明智选择。以下是各框架的简单示例代码,便于理解其基本用法。
56 0
|
18天前
|
开发者 API Windows
从怀旧到革新:看WinForms如何在保持向后兼容性的前提下,借助.NET新平台的力量实现自我进化与应用现代化,让经典桌面应用焕发第二春——我们的WinForms应用转型之路深度剖析
【8月更文挑战第31天】在Windows桌面应用开发中,Windows Forms(WinForms)依然是许多开发者的首选。尽管.NET Framework已演进至.NET 5 及更高版本,WinForms 仍作为核心组件保留,支持现有代码库的同时引入新特性。开发者可将项目迁移至.NET Core,享受性能提升和跨平台能力。迁移时需注意API变更,确保应用平稳过渡。通过自定义样式或第三方控件库,还可增强视觉效果。结合.NET新功能,WinForms 应用不仅能延续既有投资,还能焕发新生。 示例代码展示了如何在.NET Core中创建包含按钮和标签的基本窗口,实现简单的用户交互。
39 0