关于反射的一些理解

1、 什么是反射 2、 命名空间与装配件的关系 3、 运行期得到类型信息有什么用 4、 如何使用反射获取类型 5、 如何根据类型来动态创建对象 6、 如何获取方法以及动态调用方法 7、 动态创建委托
1、什么是反射         Reflection,中文翻译为反射。         这是.Net中获取运行时类型信息的方式,.Net的应用程序由几个部分:‘程序集(Assembly)’、‘模块(Module)’、‘类型(class)’组成,而反射提供一种编程的方式,让程序员可以在程序运行期获得这几个组成部分的相关信息,例如:
        Assembly类可以获得正在运行的装配件信息,也可以动态的加载装配件,以及在装配件中查找类型信息,并创建该类型的实例。 Type类可以获得对象的类型信息,此信息包含对象的所有要素:方法、构造器、属性等等,通过Type类可以得到这些要素的信息,并且调用之。 MethodInfo包含方法的信息,通过这个类可以得到方法的名称、参数、返回值等,并且可以调用之。 诸如此类,还有FieldInfo、EventInfo等等,这些类都包含在System.Reflection命名空间下。
2、命名空间与装配件的关系         很多人对这个概念可能还是很不清晰,对于合格的.Net程序员,有必要对这点进行澄清。         命名空间类似与Java的包,但又不完全等同,因为Java的包必须按照目录结构来放置,命名空间则不需要。
        装配件是.Net应用程序执行的最小单位,编译出来的.dll、.exe都是装配件。
        装配件和命名空间的关系不是一一对应,也不互相包含,一个装配件里面可以有多个命名空间,一个命名空间也可以在多个装配件中存在,这样说可能有点模糊,举个例子: 装配件A:

  1. namespace  N1
  2. {
  3. public  class  AC1  {…}
  4. public  class  AC2  {…}
  5. }
  6. namespace  N2
  7. {
  8. public  class  AC3  {…}
  9. public  class  AC4{…}
  10. }

复制代码

装配件B:

  1. namespace  N1
  2. {
  3. public  class  BC1  {…}
  4. public  class  BC2  {…}
  5. }
  6. namespace  N2
  7. {
  8. public  class  BC3  {…}
  9. public  class  BC4{…}
  10. }

复制代码

这两个装配件中都有N1和N2两个命名空间,而且各声明了两个类,这样是完全可以的,然后我们在一个应用程序中引用装配件A,那么在这个应用程序中,我们能看到N1下面的类为AC1和AC2,N2下面的类为AC3和AC4。         接着我们去掉对A的引用,加上对B的引用,那么我们在这个应用程序下能看到的N1下面的类变成了BC1和BC2,N2下面也一样。         如果我们同时引用这两个装配件,那么N1下面我们就能看到四个类:AC1、AC2、BC1和BC2。
        到这里,我们可以清楚一个概念了,命名空间只是说明一个类型是那个族的,比如有人是汉族、有人是回族;而装配件表明一个类型住在哪里,比如有人住在北京、有人住在上海;那么北京有汉族人,也有回族人,上海有汉族人,也有回族人,这是不矛盾的。
        上面我们说了,装配件是一个类型居住的地方,那么在一个程序中要使用一个类,就必须告诉编译器这个类住在哪儿,编译器才能找到它,也就是说必须引用该装配件。         那么如果在编写程序的时候,也许不确定这个类在哪里,仅仅只是知道它的名称,就不能使用了吗?答案是可以,这就是反射了,就是在程序运行的时候提供该类型的地址,而去找到它。 有兴趣的话,接着往下看吧。
3、运行期得到类型信息有什么用         有人也许疑问,既然在开发时就能够写好代码,干嘛还放到运行期去做,不光繁琐,而且效率也受影响。 这就是个见仁见智的问题了,就跟早绑定和晚绑定一样,应用到不同的场合。有的人反对晚绑定,理由是损耗效率,但是很多人在享受虚函数带来的好处的时侯还没有意识到他已经用上了晚绑定。这个问题说开去,不是三言两语能讲清楚的,所以就点到为止了。         我的看法是,晚绑定能够带来很多设计上的便利,合适的使用能够大大提高程序的复用性和灵活性,但是任何东西都有两面性,使用的时侯,需要再三衡量。
接着说,运行期得到类型信息到底有什么用呢? 还是举个例子来说明,很多软件开发者喜欢在自己的软件中留下一些接口,其他人可以编写一些插件来扩充软件的功能,比如我有一个媒体播放器,我希望以后可以很方便的扩展识别的格式,那么我声明一个接口:

  1. public  interface  IMediaFormat
  2. {
  3. string  Extension  {get;}
  4. Decoder  GetDecoder();
  5. }

复制代码

这个接口中包含一个Extension属性,这个属性返回支持的扩展名,另一个方法返回一个解码器的对象(这里我假设了一个Decoder的类,这个类提供把文件流解码的功能,扩展插件可以派生之),通过解码器对象我就可以解释文件流。 那么我规定所有的解码插件都必须派生一个解码器,并且实现这个接口,在GetDecoder方法中返回解码器对象,并且将其类型的名称配置到我的配置文件里面。 这样的话,我就不需要在开发播放器的时侯知道将来扩展的格式的类型,只需要从配置文件中获取现在所有解码器的类型名称,而动态的创建媒体格式的对象,将其转换为IMediaFormat接口来使用。
这就是一个反射的典型应用。
4、如何使用反射获取类型         首先我们来看如何获得类型信息。         获得类型信息有两种方法,一种是得到实例对象         这个时侯我仅仅是得到这个实例对象,得到的方式也许是一个object的引用,也许是一个接口的引用,但是我并不知道它的确切类型,我需要了解,那么就可以通过调用System.Object上声明的方法GetType来获取实例对象的类型对象,比如在某个方法内,我需要判断传递进来的参数是否实现了某个接口,如果实现了,则调用该接口的一个方法:

  1. public  void  Process(  object  processObj  )
  2. {
  3. Type  t  =  processsObj.GetType();
  4. if(  t.GetInterface(“ITest”)  !=null  )
  5. }

复制代码

另外一种获取类型的方法是通过Type.GetType以及Assembly.GetType方法,如:               Type  t  =  Type.GetType(“System.String”);         需要注意的是,前面我们讲到了命名空间和装配件的关系,要查找一个类,必须指定它所在的装配件,或者在已经获得的Assembly实例上面调用GetType。         本装配件中类型可以只写类型名称,另一个例外是mscorlib.dll,这个装配件中声明的类型也可以省略装配件名称(.Net装配件编译的时候,默认都引用了mscorlib.dll,除非在编译的时候明确指定不引用它),比如:           System.String是在mscorlib.dll中声明的,上面的Type  t  =  Type.GetType(“System.String”)是正确的           System.Data.DataTable是在System.Data.dll中声明的,那么: Type.GetType(“System.Data.DataTable”)就只能得到空引用。           必须: Type  t  =  Type.GetType("System.Data.DataTable,System.Data,Version=1.0.3300.0,  Culture=neutral,  PublicKeyToken=b77a5c561934e089");           这样才可以,大家可以看下面这个帖子:                 http://expert.csdn.net/Expert/to ... 2.xml?temp=.1919977           qqchen的回答很精彩
5、如何根据类型来动态创建对象         System.Activator提供了方法来根据类型动态创建对象,比如创建一个DataTable:

  1. Type  t  =  Type.GetType("System.Data.DataTable,System.Data,Version=1.0.3300.0,  Culture=neutral,  PublicKeyToken=b77a5c561934e089");
  2. DataTable  table  =  (DataTable)Activator.CreateInstance(t);

复制代码

例二:根据有参数的构造器创建对象

  1. namespace  TestSpace
  2. {
  3. public  class  TestClass
  4. {
  5. private  string  _value;
  6. public  TestClass(string  value)
  7. {
  8. _value=value;
  9. }
  10. }
  11. }
  12. Type  t  =  Type.GetType(“TestSpace.TestClass”);
  13. Object[]  constructParms  =  new  object[]  {“hello”};  //构造器参数
  14. TestClass  obj  =  (TestClass)Activator.CreateInstance(t,constructParms);

复制代码

把参数按照顺序放入一个Object数组中即可
6、如何获取方法以及动态调用方法

  1. namespace  TestSpace
  2. {
  3. public  class  TestClass  {
  4. private  string  _value;
  5. public  TestClass()  {
  6. }
  7. public  TestClass(string  value)  {
  8. _value  =  value;
  9. }
  10. public  string  GetValue(  string  prefix  )  {
  11. if(  _value==null  )
  12. return  "NULL";
  13. else
  14. return  prefix+"  :  "+_value;
  15. }
  16. public  string  Value  {
  17. set  {
  18. _value=value;
  19. }
  20. get  {
  21. if(  _value==null  )
  22. return  "NULL";
  23. else
  24. return  _value;
  25. }
  26. }
  27. }
  28. }

复制代码

上面是一个简单的类,包含一个有参数的构造器,一个GetValue的方法,一个Value属性,我们可以通过方法的名称来得到方法并且调用之,如:

  1. //获取类型信息
  2. Type  t  =  Type.GetType("TestSpace.TestClass");
  3. //构造器的参数
  4. object[]  constuctParms  =  new  object[]{"timmy"};
  5. //根据类型创建对象
  6. object  dObj  =  Activator.CreateInstance(t,constuctParms);
  7. //获取方法的信息
  8. MethodInfo  method  =  t.GetMethod("GetValue");
  9. //调用方法的一些标志位,这里的含义是Public并且是实例方法,这也是默认的值
  10. BindingFlags  flag  =  BindingFlags.Public  |  BindingFlags.Instance;
  11. //GetValue方法的参数
  12. object[]  parameters  =  new  object[]{"Hello"};
  13. //调用方法,用一个object接收返回值
  14. object  returnValue  =  method.Invoke(dObj,flag,Type.DefaultBinder,parameters,null);

复制代码

属性与方法的调用大同小异,大家也可以参考MSDN
7、动态创建委托         委托是C#中实现事件的基础,有时候不可避免的要动态的创建委托,实际上委托也是一种类型:System.Delegate,所有的委托都是从这个类派生的         System.Delegate提供了一些静态方法来动态创建一个委托,比如一个委托:

  1. namespace  TestSpace  {
  2. delegate  string  TestDelegate(string  value);
  3. public  class  TestClass  {
  4. public  TestClass()  {
  5. }
  6. public  void  GetValue(string  value)  {
  7. return  value;
  8. }
  9. }
  10. }

复制代码

使用示例:

  1. TestClass  obj  =  new  TestClass();
  2. //获取类型,实际上这里也可以直接用typeof来获取类型
  3. Type  t  =  Type.GetType(“TestSpace.TestClass”);
  4. //创建代理,传入类型、创建代理的对象以及方法名称
  5. TestDelegate  method  =  (TestDelegate)Delegate.CreateDelegate(t,obj,”GetValue”);
  6. String  returnValue  =  method(“hello”);

复制代码

时间: 2024-10-11 18:27:23

关于反射的一些理解的相关文章

Golang的反射reflect深入理解和示例

编程语言中反射的概念 在计算机科学领域,反射是指一类应用,它们能够自描述和自控制.也就是说,这类应用通过采用某种机制来实现对自己行为的描述(self-representation)和监测(examination),并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义. 每种语言的反射模型都不同,并且有些语言根本不支持反射.Golang语言实现了反射,反射机制就是在运行时动态的调用对象的方法和属性,官方自带的reflect包就是反射相关的,只要包含这个包就可以使用. 多插一句,

个人对反射应用的理解

还没有开始学习反射技术,但是个人先简单理解下,在一个类中,声明一个接口,然后执行接口的方法,如下 Inter I=new 实现这个接口的子类 如果封装这个接口的主程序不能修改,当外部对象发生改变的时候就没办法 子类.方法  以为子类不确定 为了解决这个问题,反射技术出现了,首先利用properties类读取到配置文件的信息 然后根据读取到的内容,动态的创建类 外部的程序只要实现了这个接口,然后修改下配置文件中信息 父类就可以直接执行这个方法 好吧 就到这里,只是一些个人理解~不知道对错等学了,再

java反射机制的理解

反射机制是什么概念?大多都有介绍,指的是程序在运行状态中,能够加载一个只有类名的类,加载完之后会在堆上产生一个Class对象.通过这个 Class对象可以获得类的属性.方法和其他类信息.之前对反射的应用场景感到比较模糊,今天才发现自己原来不知不觉早已经在使用着它了. 说两个场景吧: 1. spring框架中,可以通过读取配置文件,生成对象到ioc容器中,它是依赖注入的一种实现方式. <bean id="sessionFactory" class="org.springf

反射机制的理解

以前学过很长时间反射机制,很是不理解?今天终于看到一本书讲的很详细. 所有反射机制都是通过一个类叫做Class来实现: 让我看看书上是怎么介绍的 Class Class是java.lang包中的类,该类的实例用来封装对象运行时的状态.当一个类被加载且创建对象时, 和该类相关的一个类型为Claas的对象就会自动创建.Class类本身不提供构造方法,因此,不能使用new来构造对象 任何对象调用getClass()方法都可以获取和该对象相关的一个Class对象看,当然也可以有其他方法得到对象. Str

Java关于反射的加深理解

一.反射的基础 java程序中各个java类属于同一类事物,描述这类事物的java类名就是Class 比如说,很多人,用java来表示就用Person类,很多类,就用Class,Person类的实例对象比如张三.李四代表着一个个具体的人,而Class类就代表着各个类在内存中的字节码 一个类被类加载器加载进内存,会占用一片存储空间,这个空间的内容就是类的字节码,不同的类的字节码不同,所以他们在内存中的内容是不同,这些空间分别用一个一个对象来表示,这些对象具有相同的类型,这个类型就是Class 面试

java 反射类的理解与应用

本文主要解析的类是: ClassLodaer,Class,Field,Method,Constructor. 本文的目标很简单,只是对这些常用的反射类进行简单解释.对这些类中常用方法进行介绍. JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法:这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制.Java反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类:在运行时构造任意一个类的对象:在

java的反射机制,理解一下

1,java反射是什么 首先应该先了解两个概念,编译期和运行期,编译期就是编译器帮你把源代码翻译成机器能识别的代码,比如编译器把java代码编译成jvm识别的字节码文件,而运行期指的是将可执行文件交给操作系统去执行,JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意方法和属性:这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制   2,java反射(Reflection)的底层实现原理 众所周知Java有个Ob

【java基础】程序员你真的理解反射机制吗?

目录 前言 1.反射的概述 2.正式使用反射之前很有必要了解的Class类 3.反射的使用 前言 很多讲解反射的博客文章并没有详细讲解Class类,~当然包括之前的我也一样~,这样的文章只会让反射徒有其表,并不能让大多数初学者真正理解反射,而恰恰反射的原理就在于Class对象!可见他的重要性,这篇文章我将总结一下关于Class类的知识,可能还不是很全面,各位担待点哈QnQ,我之前也写过几篇关于反射的文章,主要是反射真的太重要了,现在重新总结一篇~主要是前面总结的太潦草了~,对反射重新认识顺道再结

java学习——反射机制

/* * JAVA反射机制是在运行状态中,对于任意一个类 (class文件),都能够知道这个类的所有属性和方法: * 对于任意一个对象,都能够调用它的任意一个方法和属性: * 这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制. * * 动态获取类中信息,就是java反射 . * 可以理解为对类的解剖. * * 要想要对字节码文件进行解剖,必须要有字节码文件对象. * 如何获取字节码文件对象呢? * */ 1. 通过Class clazz =Class.forName()找