如何:使用反射将委托挂钩
1. 加载包含引发事件的类型的程序集。程序集通常使用 Assembly.Load 方法加载。为了使此示例尽量简单,在当前程序集中使用了派生窗体,所以使用 GetExecutingAssembly 方法来加载当前程序集。
2. 获取表示类型的 Type 对象,并创建一个该类型的实例。由于窗体具有默认构造函数,所以在下面的代码中使用了 CreateInstance(Type) 方法。如果您创建的类型没有默认构造函数,CreateInstance 方法还有其他几种重载可供使用。新实例存储为类型 Object,以保持对程序集一无所知的状态。(通过反射可以获取程序集中的类型,而无需事先了解其名称。)
3. 获取表示该事件的 EventInfo 对象,并使用 EventHandlerType 属性来获取用于处理事件的委托类型。在下面的代码中,获取了 Click 事件的 EventInfo。
4. 获取表示处理事件的方法的 MethodInfo 对象。本主题后面示例部分中的完整程序代码包含一个与 EventHandler 委托的签名匹配的方法,该方法处理 Click 事件,但您也可以在运行时生成动态方法。有关详细信息,请参见附带的使用动态方法在运行时生成事件处理程序过程。
5. 使用 CreateDelegate 方法创建委托的实例。此方法是静态的(在 Visual Basic 中为 Shared),所以必须提供委托类型。建议使用带有 MethodInfo 的 CreateDelegate 重载。
6. 获取 add 访问器方法,并调用该方法以将事件挂钩。所有事件都具有一个 add 访问器或 remove 访问器,这些访问器被高级语言的语法隐藏。例如,C# 使用 += 运算符将事件挂钩,而 Visual Basic 则使用 AddHandler 语句。下面的代码获取 Click 事件的 add 访问器并以后期绑定方式调用它,并在委托实例中传递。参数必须作为数组传递。
7. 测试事件。下面的代码显示了在代码示例中定义的窗体。单击该窗体将调用事件处理程序。
使用动态方法在运行时生成事件处理程序
1. 使用轻量动态方法和反射发出可在运行时生成事件处理程序方法。若要构造事件处理程序,您需要知道返回类型和委托的参数类型。可以通过检查委托的 Invoke 方法来获取这些类型。下面的代码使用 GetDelegateReturnType 和 GetDelegateParameterTypes 方法获取此信息。在本主题后面的示例部分中可以找到这些方法的代码。
不需要命名 DynamicMethod,所以可以使用空字符串。在下面的代码中,最后一个参数将动态方法与当前类型相关联,从而允许委托访问 Example 类的所有公共和私有成员。
2. 生成方法体。此方法加载字符串、调用带有字符串的 MessageBox.Show 方法重载、从堆栈弹出返回值(因为处理程序没有返回类型)并返回这些值。若要了解有关发出动态方法的更多信息,请参见如何:定义和执行动态方法。
3. 通过调用动态方法的 CreateDelegate 方法完成动态方法。使用 add 访问器向事件的调用列表中添加委托。
4. 测试事件。下面的代码将加载在代码示例中定义的窗体。单击该窗体将同时调用预定义的事件处理程序和发出的事件处理程序。