C# 反射技术应用

  反射(Reflection)是.NET中的重要机制,通过放射,可以在运行时获得.NET中每一个类型(包括类、结构、委托、接口和枚举等)的成员,包括方法、属性、事件,以及构造函数等。还可以获得每个成员的名称、限定符和参数等。有了反射,即可对每一个类型了如指掌。如果获得了构造函数的信息,即可直接创建对象,即使这个对象的类型在编译时还不知道。

  1、.NET可执行应用程序结构

  程序代码在编译后生成可执行的应用,我们首先要了解这种可执行应用程序的结构。

  应用程序结构分为应用程序域—程序集—模块—类型—成员几个层次,公共语言运行库加载器管理应用程序域,这种管理包括将每个程序集加载到相应的应用程序域以及控制每个程序集中类型层次结构的内存布局。

  程序集包含模块,而模块包含类型,类型又包含成员,反射则提供了封装程序集、模块和类型的对象。我们可以使用反射动态地创建类型的实例,将类型绑定到现有对象或从现有对象中获取类型,然后调用类型的方法或访问其字段和属性。反射通常具有以下用途。

  (1)使用Assembly定义和加载程序集,加载在程序集清单中列出模块,以及从此程序集中查找类型并创建该类型的实例。
  (2)使用Module了解包含模块的程序集以及模块中的类等,还可以获取在模块上定义的所有全局方法或其他特定的非全局方法。
  (3)使用ConstructorInfo了解构造函数的名称、参数、访问修饰符(如pulic 或private)和实现详细信息(如abstract或virtual)等。使用Type的GetConstructors或GetConstructor方法来调用特定的构造函数。
  (4)使用MethodInfo了解方法的名称、返回类型、参数、访问修饰符(如pulic 或private)和实现详细信息(如abstract或virtual)等。使用Type的GetMethods或GetMethod方法来调用特定的方法。
  (5)使用FiedInfo了解字段的名称、访问修饰符(如public或private)和实现详细信息(如static)等,并获取或设置字段值。
  (6)使用EventInfo了解事件的名称、事件处理程序数据类型、自定义属性、声明类型和反射类型等,添加或移除事件处理程序。
  (7)使用PropertyInfo了解属性的名称、数据类型、声明类型、反射类型和只读或可写状态等,获取或设置属性值。
  (8)使用ParameterInfo了解参数的名称、数据类型、是输入参数还是输出参数,以及参数在方法签名中的位置等。
  System.Reflection.Emit命名空间的类提供了一种特殊形式的反射,可以在运行时构造类型。

  反射也可用于创建称为类型浏览器的应用程序,使用户能够选择类型,然后查看有关选定类型的信息。

  此外,Jscript等语言编译器使用反射来构造符号表。System.Runtime.Serialization命名空间中的类使用反射来访问数据并确定要永久保存的字段,System.Runtime.Remoting命名空间中的类通过序列化来间接地使用反射。

using System;

using System.Reflection;

namespace ReflectionExample

{

class Class1

{

[STAThread]

static void Main(string[] args)

{

System.Console.WriteLine("列出程序集中的所有类型");

Assembly a = Assembly.LoadFrom("ReflectionExample.exe");

Type[] mytypes = a.GetTypes();

foreach(Type t in mytypes)

{

System.Console.WriteLine ( t.Name );

}

System.Console.ReadLine();

System.Console.WriteLine("列出HelloWorld中的所有方法");

Type ht = typeof(HelloWorld);

MethodInfo [] mif = ht.GetMethods ();

foreach(MethodInfo mf in mif)

{

System.Console.WriteLine(mf.Name);

}

System.Console.ReadLine();

System.Console.WriteLine("实例化HelloWorld,并调用SayHello方法");

Object obj = Activator.CreateInstance(ht);

string [] s = {"ZhenLei"};

Object objName = Activator.CreateInstance(ht,s);

//BindingFlags flags = (BindingFlags.NonPublic | BindingFlags.Public |

// BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly);

MethodInfo msayhello = ht.GetMethod("SayHello");

msayhello.Invoke(obj,null);

msayhello.Invoke(objName,null);

System.Console.ReadLine();

}

}

}
using System;

namespace ReflectionExample

{

/// HelloWorld 的摘要说明。

public class HelloWorld

{

string myName = null

public HelloWorld(string name)

{

myName = name;

}

public HelloWorld() : this(null)

{

}

public string Name

{

get

{return myName;}

}

public void SayHello()

{

if (myName==null)

System.Console.WriteLine ("Hello World");

else

System.Console.WriteLine("Hello," + myName);

}

}

}

  3、在设计模式实现中使用反射技术

  采用反射技术可以简化工厂的实现。
  (1)工厂方法:通过反射可以将需要实现的子类名称传递给工厂方法,这样无须在子类中实现类的实例化。
  (2)抽象工厂:使用反射可以减少抽象工厂的子类。
  采用反射技术可以简化工厂代码的复杂程度,在.NET项目中,采用反射技术的工厂已经基本代替了工厂方法。
  采用反射技术可以极大地简化对象的生成,对以下设计模式的实现也有很大影响。
  (1)命令模式:可以采用命令的类型名称作为参数直接获得命令的实例,并且可以动态执行命令。
  (2)享元模式:采用反射技术实例化享元可以简化享元工厂。

  4. 反射的概述

  反射的定义:审查元数据并收集关于它的类型信息的能力。元数据(编译以后的最基本数据单元)就是一大堆的表,当编译程序集或者模块时,编译器会创建一个类定义表,一个字段定义表,和一个方法定义表等,。System.reflection命名空间包含的几个类,允许你反射(解析)这些元数据表的代码
   和反射相关的命名空间(我们就是通过这几个命名空间访问反射信息):

System.Reflection.MemberInfo

System.Reflection.EventInfo

System.Reflection.FieldInfo

System.Reflection.MethodBase

System.Reflection.ConstructorInfo

System.Reflection.MethodInfo

System.Reflection.PropertyInfo

System.Type

System.Reflection.Assembly

  反射的层次模型:   
  注:层次间都是一对多的关系

  反射的作用:   
  1. 可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现 有对象中获取类型  
  2. 应用程序需要在运行时从某个特定的程序集中载入一个特定的类型,以便实现某个任务时可以用到反射。   
  3. 反射主要应用与类库,这些类库需要知道一个类型的定义,以便提供更多的功能。

  应用要点:   
  1. 现实应用程序中很少有应用程序需要使用反射类型  
  2. 使用反射动态绑定需要牺牲性能   
  3. 有些元数据信息是不能通过反射获取的   
  4. 某些反射类型是专门为那些clr 开发编译器的开发使用的,所以你要意识到不是所有的反射类型都是适合每个人的。

  反射appDomain 的程序集   
  当你需要反射AppDomain 中包含的所有程序集,示例如下:

static void Main

  {

  //通过GetAssemblies 调用appDomain的所有程序集

  foreach (Assembly assem in Appdomain.currentDomain.GetAssemblies())

  {

   //反射当前程序集的信息

  reflector.ReflectOnAssembly(assem)

  }

  }

  说明:调用AppDomain 对象的GetAssemblies 方法 将返回一个由System.Reflection.Assembly元素组成的数组。

  反射单个程序集

  上面的方法讲的是反射AppDomain的所有程序集,我们可以显示的调用其中的一个程序集,system.reflecton.assembly 类型提供了下面三种方法:
  1. Load 方法:极力推荐的一种方法,Load 方法带有一个程序集标志并载入它,Load 将引起CLR把策略应用到程序集上,先后在全局程序集缓冲区,应用程序基目录和私有路径下面查找该程序集,如果找不到该程序集系统抛出异常

  2. LoadFrom 方法:传递一个程序集文件的路径名(包括扩展名),CLR会载入您指定的这个程序集,传递的这个参数不能包含任何关于版本号的信息,区域性,和公钥信息,如果在指定路径找不到程序集抛出异常。

  3. LoadWithPartialName:永远不要使用这个方法,因为应用程序不能确定再在载入的程序集的版本。该方法的唯一用途是帮助那些在.Net框架的测试环节使用.net 框架提供的某种行为的客户,这个方法将最终被抛弃不用。   
   注意:system.AppDomain 也提供了一种Load 方法,他和Assembly的静态Load 方法不一样,AppDomain的load 方法是一种实例方法,返回的是一个对程序集的引用,Assembly的静态Load 方发将程序集按值封装发回给发出调用的AppDomain.尽量避免使用AppDomain的load 方法

  利用反射获取类型信息

  前面讲完了关于程序集的反射,下面在讲一下反射层次模型中的第三个层次,类型反射   
  一个简单的利用反射获取类型信息的例子:

using system;

using sytem.reflection;

class reflecting

{

  static void Main(string[]args)

  {

  reflecting reflect=new reflecting();//定义一个新的自身类

  //调用一个reflecting.exe程序集

   assembly myAssembly =assembly.loadfrom(“reflecting.exe”)

  reflect.getreflectioninfo(myAssembly);//获取反射信息

  }

  //定义一个获取反射内容的方法

  void getreflectioninfo(assembly myassembly)

  {

    type[] typearr=myassemby.Gettypes();//获取类型

     foreach (type type in typearr)//针对每个类型获取详细信息

    {

     //获取类型的结构信息

     constructorinfo[] myconstructors=type.GetConstructors;

     //获取类型的字段信息

    fieldinfo[] myfields=type.GetFiedls()

    //获取方法信息

    MethodInfo myMethodInfo=type.GetMethods();

    //获取属性信息

    propertyInfo[] myproperties=type.GetProperties

    //获取事件信息

     EventInfo[] Myevents=type.GetEvents;

     }

  }

}

  其它几种获取type对象的方法: 
  1. System.type 参数为字符串类型,该字符串必须指定类型的完整名称(包括其命名空间)   
  2. System.type 提供了两个实例方法:GetNestedType,GetNestedTypes   
  3. Syetem.Reflection.Assembly 类型提供的实例方法是:GetType,GetTypes,GetExporedTypes  
  4. System.Reflection.Moudle 提供了这些实例方法:GetType,GetTypes,FindTypes

设置反射类型的成员
  
  反射类型的成员就是反射层次模型中最下面的一层数据。我们可以通过type对象的GetMembers 方法取得一个类型的成员。如果我们使用的是不带参数的GetMembers,它只返回该类型的公共定义的静态变量和实例成员,我们也可以通过使用带参数的GetMembers通过参数设置来返回指定的类型成员。具体参数参考msdn 中system.reflection.bindingflags 枚举类型的详细说明。
     例如:
  //设置需要返回的类型的成员内容

bindingFlags bf=bingdingFlags.DeclaredOnly|bingdingFlags.Nonpublic|BingdingFlags.Public;

foreach (MemberInfo mi int t.getmembers(bf))

{

writeline(mi.membertype) //输出指定的类型成员

}

  通过反射创建类型的实例

  通过反射可以获取程序集的类型,我们就可以根据获得的程序集类型来创建该类型新的实例,这也是前面提到的在运行时创建对象实现晚绑定的功能  
  我们可以通过下面的几个方法实现:

  1. System.Activator 的CreateInstance方法。该方法返回新对象的引用。具体使用方法参见msnd  
  2. System.Activator 的createInstanceFrom 与上一个方法类似,不过需要指定类型及其程序集   
  3. System.Appdomain 的方法:createInstance,CreateInstanceAndUnwrap,CreateInstranceFrom和CreateInstraceFromAndUnwrap   
  4. System.type的InvokeMember实例方法:这个方法返回一个与传入参数相符的构造函数,并构造该类型。   
  5. System.reflection.constructinfo 的Invoke实例方法

  反射类型的接口

  如果你想要获得一个类型继承的所有接口集合,可以调用Type的FindInterfaces GetInterface或者GetInterfaces。所有这些方法只能返回该类型直接继承的接口,他们不会返回从一个接口继承下来的接口。要想返回接口的基础接口必须再次调用上述方法。

  反射的性能:

  使用反射来调用类型或者触发方法,或者访问一个字段或者属性时clr 需 要做更多的工作:校验参数,检查权限等等,所以速度是非常慢的。所以尽量不要使用反射进行编程,对于打算编写一个动态构造类型(晚绑定)的应用程序,可以采取以下的几种方式进行代替:

  1. 通过类的继承关系。让该类型从一个编译时可知的基础类型派生出来,在运行时生成该类 型的一个实例,将对其的引用放到其基础类型的一个变量中,然后调用该基础类型的虚方法。 
  2. 通过接口实现。在运行时,构建该类型的一个实例,将对其的引用放到其接口类型的一个变量中,然后调用该接口定义的虚方法。 
  3.通过委托实现。让该类型实现一个方法,其名称和原型都与一个在编译时就已知的委托相符。在运行时先构造该类型的实例,然后在用该方法的对象及名称构造出该委托的实例,接着通过委托调用你想要的方法。这个方法相对与前面两个方法所作的工作要多一些,效率更低一些 。

时间: 2024-08-31 02:58:23

C# 反射技术应用的相关文章

Android中利用反射技术实现加减乘除

JAVA反射机制定义: JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有 属性和方法:对于任意一个对象,都能够调用它的任意一个方法:这种动态获取 的信息以及动态调用对象的方法的功能称为java语言的反射机制. Java反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类: 在运行时构造任意一个类的对象:在运行时判断任意一个类所具有的成员变量和 方法:在运行时调用任意一个对象的方法:生成动态代理. 有时候我们说某个语言具有很强的动态性,有时候我们会区分动态和静态的

java反射技术(一)

java的反射技术功能十分强大,整理一些资料!! (如需转载,请注明出处!) Lesson: 检测类examing class 1.Retrieving Class Objects 获取一个Class对象(metadata) a,从对象的实例获取.Class c = mystery.getClass();//(return Class)b,从子类的实例获取TextField t = new TextField(); Class c = t.getClass(); Class s = c.getS

C#反射技术之读取和设置类的属性

要用C#反射技术的话,首先得引入System.Reflection 命名空间,这个命名空间里的类,具有动态加载程序集.类型,动态调用方法.设置和取得属性和字段的值.可以获取类型和方法的信息的功能. 要想对一个类型实例的属性或字段进行动态赋值或取值,首先得得到这个实例或类型的Type,微软已经为我们提供了足够多的方法. 1 Class MyClass 2 { 3 private int field; 4 public int Field 5 { 6 get 7 { 8 return this.fi

JAVA:将反射技术应用于工厂模式(Factory)和单例模式(Singleton)的简单代码

反射技术大量用于Java设计模式和框架技术,最常见的设计模式就是工厂模式(Factory)和单例模式(Singleton). 参考URL: http://blog.csdn.net/xiaohai798/article/details/11640427 用接口来沟通不同程序的开发进度,不必等上游程序写好代码之后,再注入后面流程的程序员.且在实现上,可以用配置文件灵活变更,而不用重编译整个项目. InterfaceTest.java: interface InterfaceTest { //基于接

Android基于反射技术实现的加减乘除运算示例_Android

本文实例讲述了Android基于反射技术实现的加减乘除运算.分享给大家供大家参考,具体如下: JAVA反射机制定义: JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法:这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制. Java反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类:在运行时构造任意一个类的对象:在运行时判断任意一个类所具有的成员变量和方法:在运行时调用任意一个对象的方法

linq 动态条件-linq 动态添加条件,反射技术实现

问题描述 linq 动态添加条件,反射技术实现 在linq 中动态添加条件. 比如消费中会员是男的 我的参数量:消费.会员.性别 值男 如何通过反射技术实现呢. 解决方案 C#,linq, 反射?

Android中Java反射技术的使用示例

MainActivity如下: package cn.testreflect; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import android.os.Bundle; import android.app.Activity; /** * Demo描述: * Android中Java反射技术的使用示例 * 在Java中描述字节码文

Android系统原理与源码分析(1):利用Java反射技术阻止通过按钮关闭对话框

本文为原创,如需转载,请注明作者和出处,谢谢!     众所周知,AlertDialog类用于显示对话框.关于AlertDialog的基本用法在这里就不详细介绍了,网上有很多,读者可以自己搜索.那么本文要介绍的是如何随心所欲地控制AlertDialog.     现在我们来看看第一个需求:如果某个应用需要弹出一个对话框.当单击"确定"按钮时完成某些工作,如果这些工作失败,对话框不能关闭.而当成功完成工作后,则关闭对话框.当然,无论何程度情况,单击"取消"按钮都会关闭

PHP 反射技术

摘要 目标类 加载问题 加载机制 自动加载机制 怎么使用 注意问题 反射 反射属性 反射方法 反射注释 反射实例化 反射Person类 反射Grade类 执行类的方法 总结 摘要 相比于Java的反射,PHP中的反射可真的是良心之作.虽然从维护的角度来看,Java更胜一筹也更有优势.但是繁琐的处理也为Java的反射机制增加了一定的学习成本. 今天尝试着使用PHP的反射技术来获取类的信息. 核心操作可以在PHP的官方帮助文档上看到,这里用得最多的就是 getProperties getMethod