逆心 原文 反射基础,2013-4.

反射用于在程序运行过程中,获取类里面的信息或发现程序集并运行的一个过程。通过反射可以获得.dll和.exe后缀的程序集里面的信息。使用反射可以看到一个程序集内部的类,接口,字段,属性,方法,特性等信息。

一、各种GetType()、typeof的区别

  首先就是获取Tyoe对象的来源不同:

    class Program{static void Main(string[] args) { Type t1 = Type.GetType("ConsoleApplication2.Person"); //从字符串中获得Type对象  Console.WriteLine(t1.ToString()); Type t2 = typeof(ConsoleApplication2.Person); //从具体类中获得Type对象  Console.WriteLine(t2.ToString()); Person p = new Person(); Type t3 = p.GetType(); //实例,从实例中获得Type对象  Assembly ass = Assembly.LoadFrom(@"C:\Users\Administrator\Desktop\ConsoleApplication2\ConsoleApplication2\bin\Debug\ConsoleApplication2.exe"); Console.WriteLine(ass.GetType("ConsoleApplication2.Person").ToString()); //从字符串中获得Type对象 Module mod = ass.GetModules()[0]; Console.WriteLine(mod.GetType("ConsoleApplication2.Person").ToString()); //从字符串中获得Type对象  Console.ReadKey(); } }

  三者的区别在于typeof()和Type.GetType()是从一个类中获取对象,而Object.GetType()是从一个类的实例获得对象。

  而前两者的区别在于:

  • 只有typeof()是运算符。
  • Type.GetType()是实例方法。
  • Object.GetType()是基类System.Object的方法(无参数,在Type类、Assembly类、Module类中都有这个无参方法),实例方法。
  • Assembly.GetType() 、Module.GetType()、Type.Get()都是各自对象的实例方法。

在System.Reflection命名空间内包含多个反射常用的类,下面表格列出了常用的几个类。

类型 作用
Assembly 通过此类可以加载操纵一个程序集,并获取程序集内部信息
EventInfo 该类保存给定的事件信息
FieldInfo 该类保存给定的字段信息
MethodInfo 该类保存给定的方法信息
MemberInfo 该类是一个基类,它定义了EventInfo、FieldInfo、MethodInfo、PropertyInfo的多个公用行为
Module 该类可以使你能访问多个程序集中的给定模块
ParameterInfo 该类保存给定的参数信息
PropertyInfo 该类保存给定的属性信息

二、System.Reflection.Assembly类 

通过Assembly可以动态加载程序集,并查看程序集的内部信息,其中最常用的就是Load()这个方法。

Assembly assembly = Assembly.Load("MyAssembly");  

  注意在Assembly里面的加载程序集有3个方法,分别是Load、LoadFrom和LoadFile。这3个方法有什么异同呢?

  1、如果你引用了命名空间,那么就直接Load()方法,参数里面写上命名空间+类名就可以加载了。

  2、如果仅仅知道一个dll文件的那么就要用LoadFrom()方法了,参数里面直接填写完整的路径。

LoadFrom 方法具有以下缺点。请考虑改用 Load。

-如果已加载一个具有相同标识的程序集,则即使指定了不同的路径,LoadFrom 仍返回已加载的程序集。 
-如果用 LoadFrom 加载一个程序集,随后加载上下文中的一个程序集尝试加载具有相同显示名称的程序集,则加载尝试将失败。对程序集进行反序列化时,可能发生这种情况。

总结: LoadFrom只能用于加载不同标识的程序集, 也就是唯一的程序集, 不能用于加载标识相同但路径不同的程序集。

3、LoadFile (加载指定路径上的程序集文件的内容。)

  这个方法是从指定的文件来加载程序集,它是调用外部的API实现的加载方式,和上面Load,LoadFrom方法的不同之处是这个方法不会加载此程序集引用的其他程序集,也就是不会加载程序的依赖项。而同时也是不能加载相同标识的程序集的。

  利用Assembly的object CreateInstance(string)方法可以反射创建一个对象,参数0为类名。

    class Program{static void Main(string[] args) { Assembly assm = Assembly.Load("fanshe"); Console.WriteLine(assm.FullName); //输出 fanshe, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null //注释上面两行,移除程序集的引用  Assembly assm1 = Assembly.LoadFrom(@"D:\fanshe.dll"); Console.WriteLine(assm1.FullName); ////输出 fanshe, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null //与Assembly.LoadFrom基本一样,只是如果被加载的dll,还依赖其他的dll的话,被依赖的对象不会加载 Assembly assm2 = Assembly.LoadFile(@"D:\fanshe.dll"); Console.WriteLine(assm2.FullName); Console.ReadKey(); } }

三、System.Type类

Type是最常用到的类,它一般用于装载反射得到的类对象,通过Type可以得到一个类的内部信息,也可以通过它反射创建一个对象。一般有三个常用的方法可以得到Type对象。

1.利用typeof()得到Type对象

  Type type = typeof(Example);

2.利用System.Object.GetType()得到Type对象

  Example example = new Example();
Type type = example.GetType();

3.利用System.Type.GetType()得到Type对象

Type type = Type.GetType("MyAssembly.Example",false,true)   //注意0是类名,参数1表示若找不到对应类时是否抛出异常,参数2表示类名是否区分大小写

示例:

    public class Program{static void Main(string[] args) { Person p1 = new Person(); Type t1 = typeof(Person); Type t2 = p1.GetType(); Person p2 = Activator.CreateInstance(t1) as Person; Person p3 = Activator.CreateInstance(t2) as Person; Console.ReadKey(); } } public class Person { public int Id { get; set; } public string Name { get; set; } }

四、反射方法

1.通过 Type.GetMethods()能查找到类里面的方法

代码示例:

    class Program{static void Main(string[] args) { Type t = typeof(Person); MethodInfo[] MethodInfoList = t.GetMethods(); foreach (MethodInfo info in MethodInfoList) { Console.WriteLine(info); } Console.ReadKey(); } }

  输出结果如下:

    

  留意到里面所有的方法,包括继承来的都列出来了。另外可以留意到,属性的读取设置,在根本上也是一个方法。

  调用反射得到的方法使用Invoke方法(),示例如下:

        static void Main(string[] args){Assembly assembly = Assembly.Load("fanshe"); Type type = assembly.GetType("fanshe.Person"); //注意要输入全部路径,包括命名空间 object obj = Activator.CreateInstance(type); MethodInfo methodShow = type.GetMethod("Show"); //根据方法名获取MethodInfo对象 //调用无参方法Show,Invoke表示执行方法 methodShow.Invoke(obj, null); // 参数1类型为object[],代表Hello World方法的对应参数,输入值为null代表没有参数  Console.ReadKey(); }

五、反射属性

  1、通过System.Reflection.Property能查找到类里面的属性
常用的方法有GetValue(object,object[])获取属性值和SetValue(object,object,object[])设置属性值

  代码示例:

    class Program{static void Main(string[] args) { Type t = typeof(Person); PropertyInfo[] PropertyInfoList = t.GetProperties(); foreach (PropertyInfo info in PropertyInfoList) { Console.WriteLine(info); } Console.ReadKey(); } }

  输出结果如下:

    

  2、另外还可以通过PropertyInfo对象的GetValue和SetValue方法读取和设置创建出来的对象的属性值

    class Program{static void Main(string[] args) { Assembly assembly = Assembly.Load("fanshe"); Type type = assembly.GetType("fanshe.Person"); //注意要输入全部路径,包括命名空间 object obj = Activator.CreateInstance(type); //调用要属性的方法 PropertyInfo propertyName = type.GetProperty("Name"); //获取Name属性对象 propertyName.SetValue(obj, "张飞", null); //设置Name属性的值 object objName = propertyName.GetValue(obj, null); //获取属性值 Console.WriteLine(objName); //输出张飞  Console.ReadKey(); } }  

  下面给出一个方法与属性的综合示例:

class Program{static void Main(string[] args) { Assembly assembly = Assembly.Load("fanshe"); Type type = assembly.GetType("fanshe.Person"); //注意要输入全部路径,包括命名空间 object obj = Activator.CreateInstance(type); MethodInfo methodShow = type.GetMethod("Show"); //根据方法名获取MethodInfo对象 //调用无参方法Show,Invoke表示执行方法 methodShow.Invoke(obj, null); // 参数1类型为object[],代表Hello World方法的对应参数,输入值为null代表没有参数 //调用带参数方法 MethodInfo methodAdd = type.GetMethod("Add"); object[] objArr = new object[]{1,2}; methodAdd.Invoke(obj,objArr); //输出3 第二个参数为传入去的参数列表 //调用要属性的方法 PropertyInfo propertyName = type.GetProperty("Name"); //获取Name属性对象 propertyName.SetValue(obj,"张飞",null); //设置Name属性的值 PropertyInfo propertyAge = type.GetProperty("Age"); //获取Age属性对象 propertyAge.SetValue(obj, 24, null); //把Age属性设置为34 MethodInfo methodSay = type.GetMethod("Say"); methodSay.Invoke(obj,null); //输出我的名字叫张飞,我今年24岁 Console.ReadKey(); } }

  Person类的代码如下:

namespace fanshe
{public class Person{private string name; public string Name get { return name; } set { name = value; } } private int age; public int Age { get { return age; } set { age = value; } } public void Show() { Console.WriteLine("我是Person类里的Show方法!"); } public void Say() { Console.WriteLine("我的名字叫{0},我今年{1}岁", this.Name, this.Age); } public void Add(int i, int j) { Console.WriteLine(i + j); } } }

  2、根据属性的类型设置属性的值:

  我们有可能会一次过设置很多属性的值,而这些属性里面可能有字符串类型、整型等等。因此,我们需要动态设置,这是需要根据属性的类型设置属性的值。

namespace DynamicSetValue
{class Program{static void Main(string[] args) { Type type = typeof(Person); //注意要输入全部路径,包括命名空间 object obj = Activator.CreateInstance(type); //假设这是存在于XML的数据 Dictionary<string, string> dic = new Dictionary<string, string>(); dic.Add("Id", "1"); dic.Add("Name", "神灵武士"); dic.Add("Birthday", "2001-01-01"); PropertyInfo[] ProArr = type.GetProperties(); foreach (PropertyInfo p in ProArr) { if (dic.Keys.Contains(p.Name)) { p.SetValue(obj, Convert.ChangeType(dic[p.Name], p.PropertyType), null);  //当需要给属性设置不同类型的值时  } } Person person = obj as Person; Console.WriteLine(person.Birthday); Console.ReadKey(); } } //有三种不同类型的属性 public class Person { public int Id { get; set; } public string Name { get; set;} public DateTime Birthday { get; set; } } }

  输出如下:

  

  如果不根据类型来转换,则报如下错误:

  

六、反射字段

  通过 System.Reflection.FieldInfo 能查找到类里面的字段

  它包括有两个常用方法SetValue(object ,object )和GetValue(object)  因为使用方法与反射属性非常相似。

    class Program{static void Main(string[] args) { Assembly assembly = Assembly.Load("fanshe"); Type type = assembly.GetType("fanshe.Person"); //注意要输入全部路径,包括命名空间 object obj = Activator.CreateInstance(type); //调用要属性的方法 FieldInfo fieldName = type.GetField("name", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Public | BindingFlags.Instance); //获取name字段对象,后面的那个枚举参数指定,非公开字段也搜索,即读取private的name字段 fieldName.SetValue(obj, "张飞"); //设置name字段的值 object objName = fieldName.GetValue(obj); //获取属性值 Console.WriteLine(objName); //输出张飞  Console.ReadKey(); } }

七、反射特性

  通过System.Reflection.MemberInfo的GetCustomAttributes(Type,bool)就可反射出一个类里面的特性。

    class Program{static void Main(string[] args) { Assembly assembly = Assembly.Load("fanshe"); Type type = assembly.GetType("fanshe.Person"); //注意要输入全部路径,包括命名空间 object obj = Activator.CreateInstance(type); object[] typeAttributes=type.GetCustomAttributes(false); //获取Person类的特性 foreach (object attribute in typeAttributes) { Console.WriteLine(attribute.ToString()); //输出 System.SerializableAttribute 因为我在Person上里加了个[Serializable]  } Console.ReadKey(); } }

八、应用实例

  利用反射实现的简单工厂模式的多数据库系统实例:

  App.Config配置文件

<?xml version="1.0" encoding="utf-8" ?>
<configuration> <appSettings> <add key="DAL" value="ConsoleApplication2.Access"/> </appSettings> </configuration>

  主程序代码:

namespace ConsoleApplication2
{class Program{static void Main(string[] args) { Assembly assembly = Assembly.Load("ConsoleApplication2"); string str = System.Configuration.ConfigurationManager.AppSettings["DAL"]; Type type = assembly.GetType(str); //注意真正实现的对象路径写在了外面,这样要更改数据库只要改配置文件,不需要改动程序! IDAL DAL = (IDAL)Activator.CreateInstance(type); DAL.Insert(); Console.ReadKey(); } } interface IDAL { void Insert(); } class SqlServer : IDAL { public void Insert() { Console.WriteLine("SqlServer增加一条记录!"); } } class Access : IDAL { public void Insert() { Console.WriteLine("Access增加一条记录!"); } } }

  2、不引用命名空间根据路径运行dll里的方法示例

  Person类代码:

namespace fanshe
{public class Person{private string name; public string Name { get { return name; } { name = value; } } private int age; public int Age { get { return age; } set { age = value; } } public string Say(string str) { Console.WriteLine("我的名字叫{0},我今年{1}岁,另外你给我传入的参数是:{2}", this.Name, this.Age,str); return "返回结果"; } } }

  主程序代码:

    class Program{static void Main(string[] args) { //先把引用的命名空间移除 Assembly assembly = Assembly.LoadFrom(@"D:\fanshe.dll"); Type type = assembly.GetType("fanshe.Person"); object obj = Activator.CreateInstance(type); PropertyInfo proName = type.GetProperty("Name"); proName.SetValue(obj,"关羽",null); PropertyInfo proAge = type.GetProperty("Age"); proAge.SetValue(obj,24,null); MethodInfo methodSay = type.GetMethod("Say"); object[] objList = new object[1]{"传入测试参数"}; object result = methodSay.Invoke(obj,objList); Console.WriteLine(result);  //输出 返回值 Console.ReadKey(); } }

  3、获得List<T>中的T类型:

List<Dog> dogs = new List<Dog>();
Type type = dogs.GetType(); if (type.IsGenericType) {   Type[] genericArgTypes = type.GetGenericArguments();   if (genericArgTypes[0] == typeof(Dog))   {   //你想要判断的是这个吗?   } }

  当然,如果List<T>是你定义的泛型,那么直接typeof(T)更加简单。

没有整理与归纳的知识,一文不值!高度概括与梳理的知识,才是自己真正的知识与技能。 永远不要让自己的自由、好奇、充满创造力的想法被现实的框架所束缚,让创造力自由成长吧! 多花时间,关心他(她)人,正如别人所关心你的。理想的腾飞与实现,没有别人的支持与帮助,是万万不能的。
本文转自wenglabs博客园博客,原文链接:http://www.cnblogs.com/arxive/p/5799089.html,如需转载请自行联系原作者

[转] 接触C# 反射 2相关推荐

  1. c 与java 反射性能_谈谈Java 反射的快慢

    [相关学习推荐:java基础教程] 反射到底是好是坏 说到Java 中的反射,初学者在刚刚接触到反射的各种高级特性时,往往表示十分兴奋,甚至会在一些不需要使用反射的场景中强行使用反射来「炫技」.而经验 ...

  2. 大家都说 Java 反射效率低,为什么呢?

    我们在 Java 开发中,难免会接触到反射,而在一些框架中,反射的运用更是常见.我相信,每次提到反射,大家的第一反应一定是反射效率低,尽量少使用.但是反射的效率到底低多少?反射效率低的原因在哪里?这篇 ...

  3. 大家都说 Java 反射效率低,你知道原因在哪里么

    [这是 ZY 第 17 篇原创技术文章] 预备知识 了解 Java 反射基本用法 看完本文可以达到什么程度 了解 Java 反射原理及 Java 反射效率低的原因 文章概览 我们在 Java 开发中, ...

  4. dwr java有返回值但是js获取不到返回值_一探究竟:Java反射效率低的原因到底在哪?...

    预备知识 了解 Java 反射基本用法 看完本文可以达到什么程度 了解 Java 反射原理及 Java 反射效率低的原因 文章概览 我们在 Java 开发中,难免会接触到反射,而在一些框架中,反射的运 ...

  5. 关于反射程序集的心得

    近来刚好在看一些关于反射的东西,之前一直没用过,真是惭愧,后来看了些资料后,觉得好像也不怎么难,就一句话: Assembly.Load(Assembly.GetExecutingAssembly(). ...

  6. .Net 中的反射(序章) - Part.1

    引言 反射是.Net提供给我们的一件强力武器,尽管大多数情况下我们不常用到反射,尽管我们可能也不需要精通它,但对反射的使用作以初步了解在日后的开发中或许会有所帮助. 反射是一个庞大的话题,牵扯到的知识 ...

  7. Java反射的底层原理,以及Java反射的性能分析及优化

    java的反射技术,号称是编程界的九阳神功,也可以说是框架的灵魂.也正是这种反射机制使静态语言的java具备了动态语言的某些特质.就是有了反射,才让java动态,编程的时候更加灵活,能够动态获取信息以 ...

  8. 反射机制讲解,js和java反射机制的区别。

    JAVA为什么要用反射创建对象_为什么几乎所有的Java框架都要用到反射机制,她的魅力在哪里?..._18903290970的博客-CSDN博客说起Java的反射机制,大家应该不陌生吧,她是Java语 ...

  9. 2023全国特种作业操作证熔化焊接与热切割模拟考试试卷一[安考星]

    该模拟试题来源于安考星公众号 1.埋弧焊时,焊剂的存在仅能隔开熔化金属与空气的直接接触的作用. 正确答案:错误 参考解析:焊剂的存在不仅能隔开熔化金属与空气的直接接触,还能杜绝光污染及危害,而且使熔池 ...

最新文章

  1. pptpd的远程连接成功并使用
  2. 【 MATLAB 】unmkpp 函数介绍
  3. 自由自在休闲食品以创新助80后女孩成功创业
  4. bzoj 3218: a + b Problem
  5. 细谈Ehcache页面缓存的使用
  6. 云栖大会展出两款一体机,搭载新一代无影融合架构
  7. 进入实现类快捷键_实测30个自带快捷键,原来键盘也这么好用!
  8. Java中原始数据类型存放位置理解
  9. python实现多智能体一致性_多智能体深度学习算法MADDPG的PARL实践
  10. Mysql优化(出自官方文档) - 第九篇(优化数据库结构篇)
  11. 手动搭建最基础的 Retrofit + OkHttp + RxJava
  12. python numpy安装步骤-NumPy基础与安装
  13. windows 编译libtorrent
  14. 电脑重装系统后c盘数据能恢复吗?
  15. GIT无法提交到码云。原因可能是所在提交位置不对
  16. Java面向对象编程(高级部分)
  17. Java_08 快速入门 Java常用类库
  18. equest,response,session,cookie,application
  19. 创建一个整型变量toes,并将toes设置为10.
  20. 打造完美自用Ubuntu 18.04 开发环境,解决qq微信网易云

热门文章

  1. final修饰符,finally,finalize区别
  2. Ubuntu 下 Apache2 与Tomcat5 的交配指南.(转自互联网)
  3. 话里话外:参展管理信息化年会 聚会谈咨询需求有市场
  4. 详解苹果 macOS Mail 中的零点击漏洞
  5. 一个价值$1.5万的 PS NOW 漏洞
  6. 【初学】python执行系统命令四种方法比较
  7. Android 音视频深入 十四 FFmpeg与OpenSL ES 播放mp3音乐,能暂停(附源码
  8. swift:创建滚动视图的图片轮播器
  9. 完美解决office2013 错误1402
  10. discuz点歌台插件