Reflection是什么?

  Reflection(反射)是C#提供的一个允许程序访问检测修改程序自身状态或行为的重要机制。通过使用Reflection,我们可以在运行时访问程序产生的Metadata(元数据)并对Metadata进行解析,从而获得Assembly(程序集)Module(模块)或者Type(类型,包括类、结构、委托、接口和枚举等)的信息。

  举个例子,通过使用Reflection,我们可以在程序运行时动态地获取某个类型未知的对象的类型,然后调用该对象的方法或者访问该对象的字段和属性。当然,在获取到对象类型之后,我们还可以动态地创建对象。除此之外,因为Attribute编译之后会放进Metadata中,所以我们也可以通过Reflection来获取Attribute。

Reflection的优缺点

  • 优点

    1. 可以动态修改程序,降低了程序的耦合性,提高了程序的灵活性和拓展性
    2. 允许程序动态创建和控制任何类,不需要提前硬编码目标类
  • 缺点

    1. 性能损耗:前面提到,Reflection通过访问和解析Metadata使程序可以访问检测修改自身状态或行为。也就是说,Reflection本质上是一种解释操作,在操作某个程序实体之前,程序需要花时间访问Metadata去弄清楚这个程序实体是什么。因此,Reflection的效率远低于直接代码
    2. 模糊代码逻辑:因为Reflection允许程序在提前硬编码目标类的情况下动态创建和控制类,所以在源代码中不能直接看到程序的逻辑,导致使用了Reflection的代码比相应的直接代码更难理解和维护

Reflection有关的类

  根据前面的内容,我们知道Reflection的主要作用是在程序运行时获取Assembly、Module或者Type的信息。System.Reflection命名空间中的类和System.Type则为我们提供了所有能够获取这些信息的接口。

  • 抽象基类System.Type

    • 作用:
        System.Type类在Reflection中起着核心作用。作为一个抽象基类,Type类有与每种数据类型对应的派生类,通过Type类我们可以访问任何给定类型的信息
    • 获取Type引用:
      1. 使用C# typeof运算符

        1
        Type t = typeof(string);
      2. 使用对象的GetType方法

        1
        2
        string str = "";
        Type t = str.GetType();
      3. 调用Type类的静态方法GetType(需要注意的是,这里必须使用类的完全限定名命名空间+类名;如果返回null,说明在Metadata中搜索相关信息失败,需要检查是否使用了类的完全限定名)

        1
        2
        string str = "";
        Type t = Type.GetType(str);
    • 常用属性和常用方法:
属性名 说明
Name 数据类型名
FullName 数据类型的完全限定名(包括命名空间名)
Namespace 定义数据类型的命名空间名
IsAbstract 指示该类型是否是抽象类型
IsArray 指示该类型是否是数组
IsClass 指示该类型是否是类
IsEnum 指示该类型是否是枚举
IsInterface 指示该类型是否是接口
IsPublic 指示该类型是否是公有的
IsSealed 指示该类型是否是密封类
IsValueType 指示该类型是否是值类型
方法名 方法说明
GetConstructor(Type[]) 返回参数匹配传入的Type数组的public构造函数,返回类型为ConstructorInfo类型
GetConstructors() 返回所有public构造函数,返回类型为ConstructorInfo[]类型
GetEvent() 获取指定的public事件信息,返回返回EventInfo类型(该方法有多个重载版本)
GetEvents() 获取所有public事件信息,返回类型为EventInfo[]类型(该方法有多个重载版本)
GetField() 获取指定的public字段,返回类型为FieldInfo类型(该方法有多个重载版本)
GetFields() 获取所有public字段,返回类型为FieldInfo[]类型(该方法有多个重载版本)
GetInterface() 获取实现的指定接口,返回类型为InterfaceInfo类型(该方法有多个重载版本)
GetInterfaces() 获取实现的所有接口,返回类型为InterfaceInfo[]类型(该方法有多个重载版本)
GetMember() 获取指定的public成员,返回类型为MemberInfo类型(该方法有多个重载版本)
GetMembers() 获取所有public成员,返回类型为MemberInfo[]类型(该方法有多个重载版本)
GetMethod() 获取指定的public方法,返回类型为MethodInfo类型 (该方法有多个重载版本)
GetMethods() 获取所有public方法,返回类型为MethodInfo类型(该方法有多个重载版本)
GetProperty() 获取指定的public属性,返回类型为PropertyInfo类型(该方法有多个重载版本)
GetProperties() 获取所有public属性,返回类型为PropertyInfo类型(该方法有多个重载版本)
  • 命名空间System.Reflection

      System.Type用于获取程序信息的常用方法的返回类型基本都是在System.Reflection里面定义的,System.Reflection里常用的类型主要有:
类型名 类型说明
Assembly 定义和加载程序集,加载程序集清单中列出的模块,以及在此程序集中定位一个类型并创建一个它的实例
Module 保存模块信息,包括包含该模块的程序集和模块中的类,还可以获取所有全局方法或模块上定义的其它特定的非全局方法
ConstructorInfo 保存构造函数信息,如名称、参数、访问修饰符(如 public 或 private)和实现的详细信息
MethodInfo 保存方法信息,如名称、返回类型、参数、访问修饰符(如 public 或 private)和方法的实现详细信息(如 abstract 或 virtual)
FieldInfo 保存字段信息,如名称、访问修饰符(如 public 或 private)和一个字段的实现详细信息 (如 static);并获取或设置字段值
EventInfo 保存事件信息,包括名称、事件处理程序的数据类型、自定义特性、声明类型以及事件的反射的类型,并且可以添加或删除事件
PropertyInfo 保存属性信息,如名称、数据类型、声明类型,反射的类型和属性的只读或可写状态,并获取或设置属性值。
ParameterInfo 保存参数信息,如参数的名称、数据类型、参数是输入参数还是输出参数以及参数在方法签名中的位置
CustomAttributeData 发现有关自定义特性的信息,CustomAttributeData使你能够检查特性,而无需创建它们的实例
  • System.Activator类

      System.Activator类提供了CreateInstance方法来创建对象类型,因此可以配合Reflection来动态创建对象。CreateInstance方法有多个重载版本,当调用CreateInstance方法时,会根据传递给CreateInstance方法的实际参数目标类型里找到一个最匹配构造函数,并调用该构造函数创建对象。

Reflection使用示例

  • 首先创建定义用于测试的简单类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    public class Student {
    public string Name;
    public int Age { set; get; }

    public Student() {
    Name = "default";
    Age = 0;
    }

    public Student(string name, int age) {
    Name = name;
    Age = age;
    }

    public void Show() {
    Console.WriteLine("Student message: " + "name:" + Name + ", " + "age:" + Age);
    }
    }
  • 查看类中的构造方法

    ConstructorInfo
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    Student stu = new Student();
    Type type = stu.GetType();

    //获取所有构造函数
    ConstructorInfo[] constructors = type.GetConstructors();
    Console.WriteLine("Constructor Num: " + constructors.Length);
    foreach(ConstructorInfo c in constructors) {
    Console.Write("Constructor Paramter: ");
    //获取函数的参数信息
    ParameterInfo[] parameters = c.GetParameters();
    foreach(var p in parameters) {
    Console.Write(p.ParameterType.ToString() + "=" + p.Name + " ");
    }
    Console.WriteLine();
    }

    /*****output******
    Constructor Num: 2
    Constructor Paramter:
    Constructor Paramter: System.String=name System.Int32=age
    ******************/
  • 用构造函数生成对象

    ConstructorInfo.Invoke
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    Student stu = new Student();
    Type type = stu.GetType();

    Type[] pt = new Type[2];
    pt[0] = typeof(string);
    pt[1] = typeof(int);
    //根据参数列表获取匹配的构造函数
    ConstructorInfo constructor = type.GetConstructor(pt);
    Object[] obj = new object[2] { "Asan", 20 };
    //调用构造函数
    Object obj1 = constructor.Invoke(obj);
    //测试创建的结果
    ((Student)obj1).Show();

    /*****output******
    Student message: name:Asan, age:20
    ******************/
  • 使用System.Activator生成对象

    Activator.CreateInstance
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    Student stu = new Student();
    Type type = stu.GetType();

    //使用Activator创建对象,不传递参数调用默认构造函数
    Object obj2 = Activator.CreateInstance(type);
    //测试创建的结果
    ((Student)obj2).Show();

    /*****output******
    Age
    ******************/
  • 查看类中的public属性

    PropertyInfo
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    Student stu = new Student();
    Type type = stu.GetType();

    //查看public属性
    PropertyInfo[] properties = type.GetProperties();
    foreach(var property in properties) {
    Console.WriteLine(property.Name);
    }

    /*****output******
    System.Void set_Age
    System.Int32 get_Age
    ******************/
  • 查看类中的public方法

    MethodInfo
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    Student stu = new Student();
    Type type = stu.GetType();

    //查看public方法
    MethodInfo[] methods = type.GetMethods();
    foreach (var method in methods) {
    Console.WriteLine(method.ReturnType + " " + method.Name);
    }

    /*****output******
    System.Void Show
    System.String ToString
    System.Boolean Equals
    System.Int32 GetHashCode
    System.Type GetType
    ******************/
  • 查看public字段

    FieldInfo
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    Student stu = new Student();
    Type type = stu.GetType();

    //查看public字段
    FieldInfo[] fields = type.GetFields();
    foreach (var field in fields) {
    Console.WriteLine(field.Name);
    }

    /*****output******
    Name
    ******************/
  • 使用Reflection构造对象,设置字段和属性的值,并调用方法

    Invoke、Setvalue
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    Student stu = new Student();
    Type type = stu.GetType();

    //构建对象
    Object obj3 = Activator.CreateInstance(type);
    //获取字段并设置值
    FieldInfo fi = type.GetField("Name");
    fi.SetValue(obj3, "Object");
    //获取属性并设置值
    PropertyInfo pi = type.GetProperty("Age");
    pi.SetValue(obj3, 30);
    //获取方法并调用
    MethodInfo mi = type.GetMethod("Show");
    mi.Invoke(obj3, null);

    /*****output******
    Student message: name:Object, age:30
    ******************/
  • 完整代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    using System;
    using System.Reflection;

    namespace Reflection {
    public class Student {
    public string Name;
    public int Age { set; get; }

    public Student() {
    Name = "default";
    Age = 0;
    }

    public Student(string name, int age) {
    Name = name;
    Age = age;
    }

    public void Show() {
    Console.WriteLine("Student message: " + "name:" + Name + ", " + "age:" + Age);
    }
    }

    class Program {
    static void Main(string[] args) {
    Student stu = new Student();
    Type type = stu.GetType();

    //获取所有构造函数
    ConstructorInfo[] constructors = type.GetConstructors();
    Console.WriteLine("Constructor Num: " + constructors.Length);
    foreach(ConstructorInfo c in constructors) {
    Console.Write("Constructor Paramter: ");
    //获取函数的参数信息
    ParameterInfo[] parameters = c.GetParameters();
    foreach(var p in parameters) {
    Console.Write(p.ParameterType.ToString() + "=" + p.Name + " ");
    }
    Console.WriteLine();
    }

    Type[] pt = new Type[2];
    pt[0] = typeof(string);
    pt[1] = typeof(int);
    //根据参数列表获取匹配的构造函数
    ConstructorInfo constructor = type.GetConstructor(pt);
    Object[] obj = new object[2] { "Asan", 20 };
    //调用构造函数
    Object obj1 = constructor.Invoke(obj);
    //测试创建的结果
    ((Student)obj1).Show();

    //使用Activator创建对象,不传递参数调用默认构造函数
    Object obj2 = Activator.CreateInstance(type);
    //测试创建的结果
    ((Student)obj2).Show();

    //查看public属性
    PropertyInfo[] properties = type.GetProperties();
    foreach(var property in properties) {
    Console.WriteLine(property.Name);
    }

    //查看public方法
    MethodInfo[] methods = type.GetMethods();
    foreach (var method in methods) {
    Console.WriteLine(method.ReturnType + " " + method.Name);
    }

    //查看public字段
    FieldInfo[] fields = type.GetFields();
    foreach (var field in fields) {
    Console.WriteLine(field.Name);
    }

    //构建对象
    Object obj3 = Activator.CreateInstance(type);
    //获取字段并设置值
    FieldInfo fi = type.GetField("Name");
    fi.SetValue(obj3, "Object");
    //获取属性并设置值
    PropertyInfo pi = type.GetProperty("Age");
    pi.SetValue(obj3, 30);
    //获取方法并调用
    MethodInfo mi = type.GetMethod("Show");
    mi.Invoke(obj3, null);

    Console.ReadLine();
    }
    }
    }

    /*****output******
    Constructor Num: 2
    Constructor Paramter:
    Constructor Paramter: System.String=name System.Int32=age
    Student message: name:Asan, age:20
    Student message: name:default, age:0
    Age
    System.Void set_Age
    System.Int32 get_Age
    System.Void Show
    System.String ToString
    System.Boolean Equals
    System.Int32 GetHashCode
    System.Type GetType
    Name
    Student message: name:Object, age:30
    ******************/

参考链接

.NET Framework 中的反射
C#反射机制