1. 反射简介
2. 使用反射
3. 反射调用方法的执行机制
1. 反射简介
程序集包含模块,而模块包含类型,类型又包含成员。反射则提供了封装程序集、模块和类型的对象。您可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型。然后,可以调用类型的方法或访问其字段和属性。(FROM MSDN)
2. 使用反射
2.1 反射对象模型(FROM 《Essential.Net》)
2.2 反射类型的层次结构(FROM 《Essential.Net》)
2.3 各个对象的创建方式和功能
对象 | 创建该对象 | 功能(FROM MSDN) |
Assembly | Assembly.Load Assembly.LoadFile Assembly.LoadFrom | 使用 <?XML:NAMESPACE PREFIX = MSHelp NS = "http://msdn.microsoft.com/mshelp" /> 定义和加载程序集,加载在程序集清单中列出的模块,以及从此程序集中查找类型并创建该类型的实例。 |
Assembly.GetModule Assembly.GetModules | 使用 发现以下信息:包含模块的程序集以及模块中的类等。您还可以获取在模块上定义的所有全局方法或其他特定的非全局方法。 | |
Type.GetConstructor Type.GetConstructors Type.GetConstructorImpl | 使用 发现以下信息:构造函数的名称、参数、访问修饰符(如 public 或 private)和实现详细信息(如 abstract 或 virtual)等。使用 的 或 方法来调用特定的构造函数。 | |
Type.GetMethod Type.GetMethods Type.GetMethodImpl | 使用 发现以下信息:方法的名称、返回类型、参数、访问修饰符(如 public 或 private)和实现详细信息(如 abstract 或 virtual)等。 | |
Type.GetField Type.GetFields | 使用 发现以下信息:字段的名称、访问修饰符(如 public 或 private)和实现详细信息(如 static)等;并获取或设置字段值。 | |
Type.GetEvent Type.GetEvents | 使用 发现以下信息:事件的名称、事件处理程序数据类型、自定义属性、声明类型和反射类型等;并添加或移除事件处理程序。 | |
Type.GetProperty Type.GetProperties Type.GetPropertyImpl | 使用 发现以下信息:属性的名称、数据类型、声明类型、反射类型和只读或可写状态等;并获取或设置属性值。 | |
MethodBase.GetParameters | 使用 发现以下信息:参数的名称、数据类型、参数是输入参数还是输出参数,以及参数在方法签名中的位置等。 | |
当您在一个应用程序域的仅反射上下文中工作时,请使用 来了解有关自定义属性的信息。使用 ,您不必创建属性的实例就可以检查它们。 |
2.4 反射调用实例
namespace NameSpace
{
internal class Reflect
{
private int Add(int arg0, int arg1, int arg2)
{
return arg0 + arg1 + arg2;
}
}
class Program
{
internal static int CallAdd()
{
//指定TypeName创建对象实例
object target = Assembly.GetExecutingAssembly().CreateInstance("NameSpace.Reflect", true);
//取得方法
Type type = target.GetType();
MethodInfo methodInfo = type.GetMethod("Add", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
if (methodInfo == null)
return 0;
object[] args = new object[] { 10, 20, 30 };
object result = methodInfo.Invoke(target, args); //调用
return Convert.ToInt32(result);
}
}
}
3. 反射调用方法的执行机制
MethodInfo.Invoke使用提供的对象引用和参数来调用底层方法。其执行过程如下(FROM 《Essential.Net》):
(1). 构建一个堆栈帧;
(2). 将参数值拷贝到堆栈上;
(3). 调用目标方法(IA-32处理器的call指令);
(4). 方法执行完毕后,Invoke识别按引用传递的参数,并将他们拷贝回参数值数组中;
(5). 如果方法有返回值,则将该值作为Invoke的返回值。
下图展示了上面2.4中示例代码的执行过程:
补充:
1. 有关堆栈帧,可以参考:《Reversing:逆向工程揭密》 堆栈帧
2. 上图中,展示的是fastcall调用约定,fastcall调用约定通常使用ECX寄存器和EDX寄存器来分别存放第一个参数和第二个参数。有关调用约定,可以参考:《Reversing:逆向工程揭密》 调用约定