using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Windows.Forms;
class ExampleForm : Form
{
public ExampleForm() : base()
{
this.Text = "Click me";
}
}
class Example
{
public static void Main()
{
Example ex = new Example();
ex.HookUpDelegate();
}
private void HookUpDelegate()
{
//加载包含引发事件的类型的程序集。 程序集通常使用 Assembly.Load 方法加载。
//为了简化本示例,当前程序集中使用了派生窗体,因此使用 GetExecutingAssembly 方法加载当前程序集。
Assembly assem = typeof(Example).Assembly;
//获取表示类型的 Type 对象,并创建一个该类型的实例。 由于窗体具有无参数构造函数,因此下面的代码中使用了 CreateInstance(Type) 方法。
//如果要创建的类型没有无参数构造函数,CreateInstance 方法还有其他几种重载可供使用。
//新实例存储为类型 Object,以保持对程序集一无所知的假定。 (通过反射可获取程序集中的类型,无需事先知悉其名称。)
Type tExForm = assem.GetType("ExampleForm");
Object exFormAsObj = Activator.CreateInstance(tExForm);
// 获取表示该事件的 EventInfo 对象,并使用 EventHandlerType 属性来获取用于处理事件的委托类型。
// 在以下代码中,获取了 Click 事件的 EventInfo。
//********获取单击事件
EventInfo evClick = tExForm.GetEvent("Click");
Type tDelegate = evClick.EventHandlerType;
//获取表示处理事件的方法的 MethodInfo 对象。
//本主题后面“示例”部分中的完整程序代码包含一个与 EventHandler 委托的签名匹配的方法,该方法处理 Click 事件,
//但您也可以在运行时生成动态方法。 有关详细信息,请参阅附带的使用动态方法在运行时生成事件处理程序的过程。
//*************获取Example.LuckyHandler()这个方法
MethodInfo miHandler =
typeof(Example).GetMethod("LuckyHandler",
BindingFlags.NonPublic | BindingFlags.Instance);
// 使用 CreateDelegate 方法创建委托的实例。 此方法是静态的(在 Visual Basic 中为 Shared),因此必须提供委托类型。 建议使用带有 MethodInfo 的 CreateDelegate 重载。
Delegate d = Delegate.CreateDelegate(tDelegate, this, miHandler);
//获取 add 访问器方法,并调用该方法以将事件挂钩。 所有事件都有一个 add 访问器和一个 remove 访问器,这些访问器由高级语言的语法隐藏。
//例如,C# 使用 += 运算符将事件挂钩,Visual Basic 则使用 AddHandler 语句。
//以下代码获取 Click 事件的 add 访问器,然后以后期绑定方式对其进行调用,并在委托实例中传递。 参数必须作为数组传递。
MethodInfo addHandler = evClick.GetAddMethod();//类似+=
Object[] addHandlerArgs = { d };
addHandler.Invoke(exFormAsObj, addHandlerArgs);//绑定
//*********************************************************以下是绑定动态方法*********************************************************************
// 也可以在运行时生成事件处理程序方法,
// 使用轻量级动态方法和 Reflection.Emit。
// 要构造事件处理程序,您需要委托的返回类型和参数类型。 这些可以通过检查委托的 Invoke 方法获得。
// 动态方法没有必要命名,所以可以使用空字符串。 最后一个参数将动态方法与当前类型相关联,使委托可以访问 Example 的所有公共和私有成员,就好像它是一个实例方法一样。
Type returnType = GetDelegateReturnType(tDelegate);
if (returnType != typeof(void))
throw new ArgumentException("Delegate has a return type.", nameof(d));
DynamicMethod handler =
new DynamicMethod("",
null,
GetDelegateParameterTypes(tDelegate),
typeof(Example));
// 生成一个方法体。 此方法加载一个字符串,调用获取字符串的 Show 方法重载,从堆栈中弹出返回值(因为处理程序没有返回类型),然后返回。
ILGenerator ilgen = handler.GetILGenerator();
Type[] showParameters = { typeof(String) };
MethodInfo simpleShow =
typeof(MessageBox).GetMethod("Show", showParameters);
ilgen.Emit(OpCodes.Ldstr,
"This event handler was constructed at run time.动态的");
ilgen.Emit(OpCodes.Call, simpleShow);
ilgen.Emit(OpCodes.Pop);
ilgen.Emit(OpCodes.Ret);
// 通过调用其 CreateDelegate 方法完成动态方法。 使用“添加”访问器将委托添加到事件的调用列表中。
Delegate dEmitted = handler.CreateDelegate(tDelegate);
addHandler.Invoke(exFormAsObj, new Object[] { dEmitted });
// 显示表格。 单击表单会导致调用两个委托。
Application.Run((Form)exFormAsObj);
}
private void LuckyHandler(Object sender, EventArgs e)
{
MessageBox.Show("This event handler just happened to be lying around.常规绑定");
}
private Type[] GetDelegateParameterTypes(Type d)
{
if (d.BaseType != typeof(MulticastDelegate))
throw new ArgumentException("Not a delegate.", nameof(d));
MethodInfo invoke = d.GetMethod("Invoke");
if (invoke == null)
throw new ArgumentException("Not a delegate.", nameof(d));
ParameterInfo[] parameters = invoke.GetParameters();
Type[] typeParameters = new Type[parameters.Length];
for (int i = 0; i < parameters.Length; i++)
{
typeParameters[i] = parameters[i].ParameterType;
}
return typeParameters;
}
private Type GetDelegateReturnType(Type d)
{
if (d.BaseType != typeof(MulticastDelegate))
throw new ArgumentException("Not a delegate.", nameof(d));
MethodInfo invoke = d.GetMethod("Invoke");
if (invoke == null)
throw new ArgumentException("Not a delegate.", nameof(d));
return invoke.ReturnType;
}
}