什么是反射?

反射是.net framework提供的一个帮助类库,可以访问dll/exe的metadata(元数据),并且使用他们。

元数据Metadata),又称中介数据中继数据,是为了描述数据的数据,主要是描述数据属性的信息,用来支持如指示存储位置、历史数据、资源查找、文件记录等功能。

使用反射

简单使用

  1. #region 用反射机制获取程序集中的属性与方法(元数据)
  2. {
  3. // 获取所在的dll的信息
  4. foreach (var item in assembly.GetModules())
  5. {
  6. // 获取dll的名称
  7. Console.WriteLine(item.Name);
  8. }
  9. // 获取dll的类型 {Name = "Student" FullName = "Models.Student"}
  10. foreach (var type in assembly.GetTypes())
  11. {
  12. Console.WriteLine(type.Name);
  13. // 获取指定类型的方法,方法中包含{字段的get,set方法、自定义方法、默认方法(Equals、GetHashCode、GetType、ToString等)}
  14. foreach (var method in type.GetMethods())
  15. {
  16. Console.WriteLine(method.Name);
  17. }
  18. }
  19. }
  20. #endregion

反射调用构造函数(IOC的雏形)

反射调用无参数构造函数

  1. #region 用反射的机制创建对象(调用无参的构造函数)
  2. {
  3. // 获取对应类型
  4. Type type = assembly.GetType("Models.Student");
  5. // 创建对象
  6. object vobj = Activator.CreateInstance(type);
  7. // 使用对象记得转换对象类型
  8. Student student = vobj as Student;
  9. // 使用对象方法
  10. student.write();
  11. }
  12. #endregion

反射调用带参数的构造函数

  1. #region 调用带参数的构造函数
  2. {
  3. Type type = assembly.GetType("Models.Student");
  4. //创建一个带两个参数的构造函数
  5. object obj = Activator.CreateInstance(type, new object[] { 1,"zs" });
  6. //使用方法
  7. Student student = obj as Student;
  8. student.write();
  9. }
  10. #endregion

反射调用泛型类构造

  1. #region 获取泛型类,调用泛型构造
  2. {
  3. //这里注意,使用`2的形式,指定类型的泛型参数格式
  4. Type type = assembly.GetType("Models.GenericStudent`2");
  5. Type typeGenereic = type.MakeGenericType(typeof(int), typeof(string));
  6. //调用泛型构造函数,构建对象
  7. object obj = Activator.CreateInstance(typeGenereic,new object[] { 1,"lisi"});
  8. //使用方法
  9. GenericStudent<int, string> student = obj as GenericStudent<int,string>;
  10. student.write();
  11. }
  12. #endregion

反射调用私有构造函数

  1. #region 反射调用私有构造函数
  2. {
  3. // 用这种方式可以破坏单例模式
  4. Type type = assembly.GetType("Models.Teacher");
  5. // 调用私有构造函数,指定nonpublic为true,代表可以反问私有的构造方法。
  6. object obj = Activator.CreateInstance(type, true);
  7. }
  8. #endregion

反射调用方法

反射调用普通方法

  1. #region 反射调用方法
  2. {
  3. Type type = assembly.GetType("Models.Student");
  4. object vobj = Activator.CreateInstance(type);
  5. MethodInfo methodInfo = type.GetMethod("write");
  6. methodInfo.Invoke(vobj, null);
  7. }
  8. #endregion

反射调用特殊方法(带参数的、静态的、重载的、私有的、泛型的)

13_C#之反射 - 图1

13_C#之反射 - 图2

调用泛型方法

13_C#之反射 - 图3

反射动态获取/赋值属性字段

  1. #region 反射动态获取/赋值属性字段
  2. //通常当使用到一个实体类的反射时,是不会从头(程序集Assmbly找起的)
  3. {
  4. Type type = typeof(Student);
  5. // 实例化当前类型
  6. object obj = Activator.CreateInstance(type);
  7. //遍历获取类型判断并赋值
  8. foreach (var item in type.GetProperties())
  9. {
  10. if (item.Name.Equals("id"))
  11. {
  12. item.SetValue(obj,1);
  13. }
  14. if (item.Name.Equals("name"))
  15. {
  16. item.SetValue(obj, "lisi");
  17. }
  18. }
  19. }
  20. #endregion

泛型的好处与局限

好处:动态,将写死的东西可以用反射来动态来创建。

局限:

1、代码繁琐

2、反射能避开编译器的语法检查、编译检查,运行时才报错

3、性能问题(不是很大的问题):反射是普通方法的性能损耗百倍以上,但是绝对值还是蛮小的,几乎不影响项目的性能。

反射和缓存是离不开的,通常将固定的的反射的一些步骤缓存起来。而上一章的泛型缓存就非常适合。性能很高。