很全很好用的反射例子 - 范文中心

很全很好用的反射例子

07/10

反射帮助类

这个帮助类主要是用反射技术来实现的,既然说到反射那我们就来说说反射吧!

1、概念:这是.Net中获取运行时类型信息的方式,.Net的应用程序由几个部分:'程序集(Assembly)’、'模块(Module)’、'类型(class)’组成,而反射提供一种编程的方式,让程序员可以在程序运行期获得这几个组成部分的相关信息,例如: 通常程序员面试题,有这样关于反射的解释:反射可以动态地创建类型的实例,还可以将类型绑定到现有对象,或从现有对象中获取类型。然后,可以调用类型的方法或访问其字段和属性。

2、下面我们来说说反射中经常用到的几个类吧!

a) Assembly类可以获得正在运行的装配件信息,也可以动态的加载装配件,以及在装配件中查找类型信息,并创建该类型的实例。

i. 下面是关于Assembly类的例子

public void AssemblyTest()

{

Console.WriteLine("----------------Assembly 类的使用----------------"); Console.WriteLine();

//获取当前所执行代码的程序集信息

Assembly assembly = Assembly.GetExecutingAssembly(); Console.WriteLine("获取程序集的位置:"+ assembly.CodeBase); Console.WriteLine("获取程序集的入口点:"+assembly.EntryPoint); Console.WriteLine("获取程序集的显示名称:"+assembly.FullName); Console.WriteLine("获取包含当前程序集清单的模块:"+assembly.ManifestModule); Console.WriteLine(); //获取当前程序集的名称和信息 AssemblyName assemblyName = assembly.GetName(); Console.WriteLine("获取或设置程序集的简单名称:"+assemblyName.Name); Console.WriteLine("获取程序集的名称:"+assemblyName.FullName); Console.WriteLine("获取或设置程序集的URL位置:"+assemblyName.CodeBase); Console.WriteLine("获取或设置程序集的主版本号、次版本号、内部版本号和修订版本号: "+assemblyName.Version);

Console.WriteLine(); } //获取当前程序集的版本相关信息 Version version = assemblyName.Version; Console.WriteLine("获取当前程序集的主版本号:"+version.Major); Console.WriteLine("获取当前程序集的次版本号:" + version.Minor); Console.WriteLine("获取当前程序集的内部版本号:" + version.Build); Console.WriteLine("获取当前程序集的修订版本号:" + version.MajorRevision); Console.WriteLine();

ii.

b) Type类可以获得对象的类型信息,此信息包含对象的所有要素:方法、构造器、属性等等,通过Type类可以得到这些要素的信息,并且调用之。

i. 下面是关于Type类的例子:

public void TypeTest()

{

Console.WriteLine("-----------------------Type类的使用-------------------------"); Console.WriteLine(); //设置被检索的类 Type myType = Type.GetType("Demo.PersonClass"); //Type myType = new PersonClass().GetType(); //检索信息 Console.WriteLine("获取当前成员名称:"+myType.Name); Console.WriteLine("获取当前完全限定名(不包括程序信):" + myType.FullName); Console.WriteLine("获取当前Type所在的够命名空间:"+myType.Namespace); Console.WriteLine(); //检索类成员 Console.WriteLine("获取方法相关信息:"+myType.GetMethod("MetName").ToString()); Console.WriteLine("获取属性相关信息:"+myType.GetProperty("Name").ToString());

Console.WriteLine("获取字段相关信息:"+ myType.GetField("name",BindingFlags.NonPublic |

BindingFlags.Instance).ToString());

}

Console.WriteLine(); //设定自己为被检索的类 Type thisType = this.GetType();

c) 访问类成员中的常用到的几个类:

///

/// 访问类成员± /// public void ClassMemberInfo() {

//指定被访问的类

//Type myType = Type.GetType("Demo.PersonClass")

//或者这样指定被访问的类:这样可以获取属性值但要用到对象实例,

PersonClass person = new PersonClass();

Type personType = person.GetType(); Console.WriteLine("-----------MemberInfo访问类的所有成员----------"); Console.WriteLine();

//MemberInfo类:遍历访问类中所有成员 MemberInfo[] memberInfo = personType.GetMembers(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly); foreach (MemberInfo m in memberInfo) { } Console.WriteLine(); Console.WriteLine("成员名称:{0} ----------- 成员类型:{1}", m.Name, m.MemberType);

Console.WriteLine(); //MethodInfo类:遍历被访问类的方法 MethodInfo[] methodInfo = personType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);

foreach (MethodInfo m in methodInfo) { } Console.WriteLine(); Console.WriteLine("------------------PropertyInfo类访问属性------------------"); Console.WriteLine(); Console.WriteLine("方法名称:{0} ----------- 方法类型:{1}, {2}", m.Name, m.ReturnType); //Propertyinfo类:遍历被访问类的属性 PropertyInfo[] prop = personType.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);

foreach (PropertyInfo p in prop) {

}

Console.WriteLine();

Console.WriteLine("---------------------------FieldInfo类访问字段------------------------------");

Console.WriteLine(); Console.WriteLine("属性名称:{0} 属性类型:{1} 属性值:{2}", p.Name, p.PropertyType, p.GetValue(person, null));

//FieldInfo类:遍历被访问类的字段 FieldInfo[] fieldInfo = personType.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);

foreach (FieldInfo f in fieldInfo) { } Console.WriteLine(); Console.WriteLine("字段名称:{0} --------- 字段类型:{1}", f.Name, f.FieldType); Console.WriteLine("---------------ConstructorInfo类访问构造函数------------"); Console.WriteLine(); //ConstructorInfo类:遍历被访问类的构造函数 ConstructorInfo[] constructor = personType.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);

foreach (ConstructorInfo c in constructor) { Console.WriteLine("构造函数名称:{0} ------- 构造函数类型:{1}", c.Name, c.MemberType);

Console.WriteLine(); Console.WriteLine("----------------EventInfo类访问类的事件元数据---------------"); Console.WriteLine(); //EventInfo类:遍历被访问类的事件 EventInfo[] eventInfo = personType.GetEvents(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);

} foreach (EventInfo e in eventInfo) { } Console.WriteLine(); Console.WriteLine("事件名称:{0} -------- 成员类型:{1}", e.Name, e.MemberType); Console.WriteLine("--------------ParameterInfo用于表示参数元数据-----------"); Console.WriteLine(); //ParameterInfo类:检索PersonClass类中MetName()方法中的参数 MethodInfo method = personType.GetMethod("TestName"); //("TestName")为方法名 ParameterInfo[] para = method.GetParameters(); int count = 0; foreach (ParameterInfo p in para) { } Console.WriteLine(); count++; Console.WriteLine("参数" +count+ "名称:{0}, 类型:{1}", p.Name, p.ParameterType);

d) 调用类成员

///

/// 调用类成员 /// 第一种调用方法就是用MethodInfo类调用方法,PropertyInfo类调用属性,FieldInfo类调用字段,EventInfo类调用事件, /// ConstructorInfo类调用构造函数

/// 第二种方法就是用Type类的InvokeMember()方法

///

public void OperMembers()

{

//指定被访问的类

PersonClass personClass = new PersonClass();

Type type = personClass.GetType();

// 或者这样指定被访问类(注意:静态类时(“GetType(“命名空间.类名”)”)) //Type type = Type.GetType("Demo.PersonClass");

} //操作构造函数 ConstructorInfo constructor = type.GetConstructor(System.Type.EmptyTypes); //操作事件 EventInfo eventInfo = type.GetEvent("WMShout"); //("WMShout")表示的是事件名 Console.WriteLine("声明该成员的类:"+eventInfo.DeclaringType); Console.WriteLine("事件名称:"+eventInfo.Name); Console.WriteLine("事件类型:"+eventInfo.MemberType); Console.WriteLine(); //操作字段 FieldInfo field = type.GetField("name", BindingFlags.NonPublic | BindingFlags.Instance); field.SetValue(personClass, "hehe"); //"hehe" 表示给字段赋的新值 Console.WriteLine("操作字段改变后的值为:"+field.Name ); Console.WriteLine(); //操作属性 PropertyInfo property = type.GetProperty("Name"); //("Name")表示属性名 property.SetValue(personClass, "wxy", null); //"wxy"为新值 SetValue为设置属性的值,GetValue为获取属性的值 Console.WriteLine("操作属性改变后的值为:"+personClass.Name); //操作方法 string[] strName = new String[] { "我是谁" }; //方法参数的值 MethodInfo methodInfo = type.GetMethod("MetName"); //("MetName")是方法名 methodInfo.Invoke(personClass, strName); Console.WriteLine("操作方法改变值后为:" + personClass.Name);

下面是我封装的一个Helper类,这个类主要用于一个对象给另一个对象赋值(就是一个对象中的属性或字段想要得到与另一个对象相同的值那么就可以可以用这封装的这个类):

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Reflection;

using System.Collections;

using System.IO;

namespace ReflectionDemo

{

public class ReflectionHelper

{

///

/// 将一个对象中的属性值赋给对应的另一个对象中的属性

///

/// 被赋值的对象

/// 赋值的对象

public static void GetObjectAttributeAssignmentAnotherObject(object target, object initial)

{

//获取被赋值对象的属性

PropertyInfo[] propertyInfo1 = target.GetType().GetProperties(BindingFlags.Public |

BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);

//获取赋值对象的属性

PropertyInfo[] propertyInfo2 = initial.GetType().GetProperties(BindingFlags.Public |

BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);

foreach (PropertyInfo property in propertyInfo1) //遍历被赋值对象的属性

{

foreach (PropertyInfo p in propertyInfo2) //遍历赋值对象的属性

{

//判断被赋值对象与赋值对象中的属性名和属性类型都同那就赋值

if (property.Name == p.Name && property.PropertyType == p.PropertyType && property.CanWrite == true) {

property.SetValue(target, p.GetValue(initial, null), null); //向对象设置值(SetValue为置,GetValue为获取) }

}

}

}

///

/// 将一个对象中的属性值赋给对应的另一个对象中的属性

///

/// 被赋值的对象

/// 赋值的对象

/// 保存两个对象中不一样的属性(被赋值的保存成Key,赋值的保存成Value)

public static void SetObjectAttributes(object target, object initial,Hashtable ht)

{

//获取被赋值对象的属性

PropertyInfo[] propertyInfo1 = target.GetType().GetProperties(BindingFlags.Public |

BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);

//获取赋值对象的属性

PropertyInfo[] propertyInfo2 = initial.GetType().GetProperties(BindingFlags.Public |

BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);

foreach (PropertyInfo property in propertyInfo1) //遍历被赋值对象的属性

{

foreach (PropertyInfo p in propertyInfo2) //遍历赋值对象的属性

{

if (ht.Count > 0) //保证Hashtable中有数据

{

if (ht[property.Name] != null) //判断Hashtable中的key值在Hashtable中是否能找到

{

if (ht[property.Name].Equals(p.Name)) //判断两个对象中和的属性在Hashtable中是否是相对应

{

property.SetValue(target, p.GetValue(initial, null), null);//赋值(SetValue为设置值,GetValue取值) continue;

}

}

}

//判断被赋值对象与赋值对象中的属性名和属性类型都相同那就赋值

if (property.Name == p.Name && property.PropertyType == p.PropertyType && property.CanWrite == true) {

property.SetValue(target, p.GetValue(initial, null), null);

}

}

}

}

///

/// 将一个对象中的字段值赋给对应的另一个对象中的字段

///

/// 需要被赋值的对象

/// 已经有值的对象

public static void SetObjectField(object target, object initial)

{

//获取被赋值对象中的字段

FieldInfo[] fieldInfo1 = target.GetType().GetFields(BindingFlags.Public |

BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);

//获取赋值对象中的字段

FieldInfo[] fieldInfo2 = initial.GetType().GetFields(BindingFlags.Public |

BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);

foreach (FieldInfo field in fieldInfo1)

{

foreach (FieldInfo f in fieldInfo2)

{

//判断被赋值对象与赋值对象的名称与类型是否都相同

if (field.Name == f.Name && field.FieldType == f.FieldType)

{

field.SetValue(target, f.GetValue(initial)); //赋值(SetValue为设置值,GetValue为获取值)

}

}

}

}

///

/// 将一个对象中的属性值赋给对应的另一个对象中的属性(包含不一样的属性名称,但要一一对应)

///

/// 被赋值对象

/// 赋值对象

/// 这个集合存放两个对象中不一样属性名称的,被赋值对象属性被存放为Key,赋值对象被存放为Value public static void GetObjectAttributeAssignmentAnotherObject(object target, object initial, IDictionary dic) {

//获取被赋值对象的属性

PropertyInfo[] propertyInfoObj1 = target.GetType().GetProperties(BindingFlags.Public |

BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);

//获取赋值对象的属性

PropertyInfo[] propertyInfoObj2 = initial.GetType().GetProperties(BindingFlags.Public |

BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);

foreach (PropertyInfo property in propertyInfoObj1) //遍历被赋值对象的属性

{

foreach (PropertyInfo p in propertyInfoObj2)

{

if (dic.Count > 0)

{

//判断dic对象中Key值是否存在,如果不存在但以用了的话那就会出KeyNotFoundException异常

if (dic.Keys.Contains(property.Name) && dic[property.Name].Equals(p.Name))

{

property.SetValue(target, p.GetValue(initial, null), null);

continue;

}

}

if (property.Name == p.Name && property.PropertyType == p.PropertyType && property.CanWrite == true) {

property.SetValue(target, p.GetValue(initial, null), null);

}

}

}

}

}

}

反射在下列情况下很有用:

需要访问程序元数据的属性。请参见主题使用反射访问属性。

检查和实例化程序集中的类型。

在运行时构建新类型。使用 System.Reflection.Emit 中的类。

执行后期绑定,访问在运行时创建的类型的方法。请参见主题动态加载和使用类型。

反射的一般概念:

反射提供了封装程序集、模块和类型的对象。您可以使用反射动态地创建类型的实例,将类型绑定到现有对 象,或从现

有对象中获取类型。然后,可以调用类型的方法或访问其字段和属性。我觉得这个已经是对反射比较干脆利落 的诠释。这里的”动态”二字非常重要,即指的是运行时刻,在运行的时刻我们可以根据程序逻辑或外部要求(比如配置文件等)创建类型的实例,然后实现象用new构造对象一样同等的效果。当然构造了这个实例之后下来的访问和以前就一样。

反射的效率:

采用反射构造对象的实例,机器明显出现延迟,不言而喻,反射是以牺牲效率为代价的。

优点:

1.反射是一个非常优秀的代码生成替代工具,能够显著减少代码长度,并缓解应用维护压力。

2.可以降低不同模块之间的依赖关系,大大提高可维护性。

缺点:

反射是以牺牲效率为代价的即消耗性能大。

下面是测试反射性能的代码:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

namespace WindowsFormsApplication1

{

public class CTester

{

private double a;

public CTester()

{

a = 10;

}

public void test1()

{

a = (a - 0.0001) * 1.0001;

}

public double Geta()

{

return a;

}

}

}

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Linq;

using System.Text;

using System.Windows.Forms;

using System.Reflection;

namespace WindowsFormsApplication1

{

public partial class Form1 : Form

{

public Form1()

{

InitializeComponent();

}

private void Form1_Load(object sender, EventArgs e)

{

}

private void button1_Click(object sender, EventArgs e)

{

int dt1 = DateTime.Now.Minute * 60000 + DateTime.Now.Second * 1000 + DateTime.Now.Millisecond;

CTester aTest = new CTester();

for (int i = 0; i

{

for (int j = 0; j

{

aTest.test1();

}

}

int dt2 = DateTime.Now.Minute * 60000 + DateTime.Now.Second * 1000 + DateTime.Now.Millisecond; int spand = dt2 - dt1;

label1.Text = "用掉时间:" + spand.ToString();

label3.Text = "值为:" + aTest.Geta();

//test1();

}

private void button2_Click(object sender, EventArgs e)

{

int dt1 = DateTime.Now.Minute * 60000 + DateTime.Now.Second * 1000 + DateTime.Now.Millisecond;

//如果将下面两个句话放入循环中,时间会用的更久

Type theTest = Type.GetType("WindowsFormsApplication1.CTester");

object theobj = theTest.InvokeMember(null, BindingFlags.CreateInstance, null, null, null);

for (int i = 0; i

{

for (int j = 0; j

{

theTest.InvokeMember("test1", BindingFlags.InvokeMethod, null, theobj, new object[0]); }

}

CTester thewar = theobj as CTester;

int dt2 = DateTime.Now.Minute * 60000 + DateTime.Now.Second * 1000 + DateTime.Now.Millisecond; int spand = dt2 - dt1;

label2.Text = "用掉时间:" + spand.ToString();

label4.Text = "值为:" + thewar.Geta();

//test2();

}

//首先我们对于对象的构造进行测试

//测试代码如下

private void test1()

{

label1.Text = "";

label3.Text = "";

int dt1 = DateTime.Now.Minute * 60000 + DateTime.Now.Second * 1000 + DateTime.Now.Millisecond;

for (int i = 0; i

{

for (int j = 0; j

{

CTester aTest = new CTester();

}

}

int dt2 = DateTime.Now.Minute * 60000 + DateTime.Now.Second * 1000 + DateTime.Now.Millisecond; int spand = dt2 - dt1;

label1.Text = "用掉时间:" + spand.ToString();

}

private void test2()

{

label2.Text = "";

label4.Text = "";

int dt1 = DateTime.Now.Minute * 60000 + DateTime.Now.Second * 1000 + DateTime.Now.Millisecond; for (int i = 0; i

{

for (int j = 0; j

{

Type theTest = Type.GetType("WindowsFormsApplication1.CTester");

object theobj = theTest.InvokeMember(null, BindingFlags.CreateInstance, null, null, null); }

}

int dt2 = DateTime.Now.Minute * 60000 + DateTime.Now.Second * 1000 + DateTime.Now.Millisecond; int spand = dt2 - dt1;

label2.Text = "用掉时间:" + spand.ToString();

}

}

}

//虽然只用invokemember尝试了一些简单的反射,但是很显然的,反射得消耗是非常大


相关内容

  • 产后的注意事项
    产后的注意事项 ● 及早给BB 吮吸乳头.分娩后半小时内让婴儿吸吮乳头,这样可尽早建立催乳和排乳反射,促进乳汁分泌.同时利于子宫收缩.第一次哺乳时间以5-10分钟为宜.产后第一天,产妇身体虚弱.伤口疼痛,可选用侧卧位学习喂奶.多数产妇分娩后 ...
  • 从[鲁豫有约]看娱乐访谈节目主持人的应变
    从<鲁豫有约>看娱乐访谈节目主持人的应变 摘要: 随着经济社会的迅速发展,人们的生活水平大大地提高,与之伴随的是人们对休闲娱乐的看法和方式也得到了巨大的改变.娱乐访谈类节目正是在这样的背景下应运而生并呈现良好的发展态势,使得越来 ...
  • 有关电动自行车的考题赏析
    有关电动自行车的考题赏析 以自行车为背景的中考试题赏析 一.考点指要 中国是自行车的消费大国,自行车早已成为普通中国老百姓家庭中的必备交通工具:同时从自行车的结构和使用来看,它又应用了许多物理知识.因此在近年中考试题中,出题者就抓住了学生特 ...
  • 初中二年级物理上册提纲
    初二物理上册提纲 第一章 声现象 一.声音的产生与传播 1. 物体是由物体振动产生的.振动停止发声就停止. 2. 声音的传播需要介质,真空不能传声. 3. 声速的大小与介质的种类和温度有关. V 固 > V液 > V气 声音在1 ...
  • 小学五上科学作业本答案
    小学科学五上<作业本>答案 生物与环境单元 1种子发芽实验(一) 1.判断题.(1)× (2)√ (3)√ 2种子发芽实验(二) 1.选择题.(1)C (2)根据实际情况选择 (3)根据实际情况选择 2.根据自己的实验情况填写. ...
  • 第2章 反褶积-1
    第二章 反褶积 反褶积是借助压缩基本地震子波来改善时间分辨率的一种处理过程.为搞清这一过程要求综合研究正演问题,即必须首先研究记录的地震道的积木式分段单元.地层是由不同类型岩性的岩层组成的,每种岩石类型都有地球物理学家所可利用的某种物理特性 ...
  • 耶鲁心理学导论学习笔记
    第一节课 Introduction 教材:彼得·格雷的<心理学>第五版 阅读书目:格雷·马库斯<诺顿读本> 如何学好这门课? 1. 不要缺课 2. 在课前阅读好书本 3. 强烈建议大家组织学习小组 心理学研究领域: ...
  • 15小露珠
    15 小露珠 教学要求: 1.能正确.流利.有感情地朗读课文. 2.学会本课生字,其中田字格上面的生字只识不写.理解由生字组成的词语.用"越**越**"造句. 3.理解课文,学习小露珠牺牲自己,把美丽奉献给大家的无私品格 ...
  • 等厚干涉牛顿环实验报告
    等厚干涉--牛顿环 等厚干涉是薄膜干涉的一种.薄膜层的上下表面有一很小的倾角是,从光源发出的光经上下表面反射后在上表面附近相遇时产生干涉,并且厚度相同的地方形成同一干涉条纹,这种干涉就叫等厚干涉.其中牛顿环是等厚干涉的一个最典型的例子,最早 ...
  • 大学物理期末论文之多普勒效应
    大学物理期末论文之多普勒效应 13125244 吴祥昇 生活实例 当一辆救护车迎面驶来的时候,听到声音越来越高:而车离去的时候声音越来越低.你可能没有意识到,这个现象和医院使用的彩超同属于一个原理,这就是"多普勒效应". ...