



























如何:使用反射将委托挂钩
1. 加载包含引发事件的类型的程序集。程序集通常使用 Assembly.Load 方法加载。为了使此示例尽量简单,在当前程序集中使用了派生窗体,所以使用 GetExecutingAssembly 方法来加载当前程序集。
Assembly assem = Assembly.GetExecutingAssembly();

2. 获取表示类型的 Type 对象,并创建一个该类型的实例。由于窗体具有默认构造函数,所以在下面的代码中使用了 CreateInstance(Type) 方法。如果您创建的类型没有默认构造函数,CreateInstance 方法还有其他几种重载可供使用。新实例存储为类型 Object,以保持对程序集一无所知的状态。(通过反射可以获取程序集中的类型,而无需事先了解其名称。)
Type tExForm = assem.GetType("ExampleForm");
Object exFormAsObj = Activator.CreateInstance(tExForm);

EventInfo evClick = tExForm.GetEvent("Click");
Type tDelegate = evClick.EventHandlerType;

4. 获取表示处理事件的方法的 MethodInfo 对象。本主题后面示例部分中的完整程序代码包含一个与 EventHandler 委托的签名匹配的方法,该方法处理 Click 事件,但您也可以在运行时生成动态方法。有关详细信息,请参见附带的使用动态方法在运行时生成事件处理程序过程。
MethodInfo miHandler =
typeof(Example).GetMethod("LuckyHandler",
BindingFlags.NonPublic | BindingFlags.Instance);

Delegate d = Delegate.CreateDelegate(tDelegate, this, miHandler);
MethodInfo addHandler = evClick.GetAddMethod();
Object[] addHandlerArgs = { d };
addHandler.Invoke(exFormAsObj, addHandlerArgs);

Application.Run((Form) exFormAsObj);

1. 使用轻量动态方法和反射发出可在运行时生成事件处理程序方法。若要构造事件处理程序,您需要知道返回类型和委托的参数类型。可以通过检查委托的 Invoke 方法来获取这些类型。下面的代码使用 GetDelegateReturnType 和 GetDelegateParameterTypes 方法获取此信息。在本主题后面的示例部分中可以找到这些方法的代码。
不需要命名 DynamicMethod,所以可以使用空字符串。在下面的代码中,最后一个参数将动态方法与当前类型相关联,从而允许委托访问 Example 类的所有公共和私有成员。
Type returnType = GetDelegateReturnType(tDelegate);
if (returnType != typeof(void))
throw new ApplicationException("Delegate has a return type.");

DynamicMethod handler =
new DynamicMethod("",
null,
GetDelegateParameterTypes(tDelegate),
typeof(Example));

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);

3. 通过调用动态方法的 CreateDelegate 方法完成动态方法。使用 add 访问器向事件的调用列表中添加委托。
Delegate dEmitted = handler.CreateDelegate(tDelegate);
addHandler.Invoke(exFormAsObj, new Object[] { dEmitted });

4. 测试事件。下面的代码将加载在代码示例中定义的窗体。单击该窗体将同时调用预定义的事件处理程序和发出的事件处理程序。
Application.Run((Form) exFormAsObj);
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()
{
// Load an assembly, for example using the Assembly.Load
// method. In this case, the executing assembly is loaded, to
// keep the demonstration simple.
//
Assembly assem = Assembly.GetExecutingAssembly();

// Get the type that is to be loaded, and create an instance
// of it. Activator.CreateInstance has other overloads, if
// the type lacks a default constructor. The new instance
// is stored as type Object, to maintain the fiction that
// nothing is known about the assembly. (Note that you can
// get the types in an assembly without knowing their names
// in advance.)
//
Type tExForm = assem.GetType("ExampleForm");
Object exFormAsObj = Activator.CreateInstance(tExForm);

// Get an EventInfo representing the Click event, and get the
// type of delegate that handles the event.
//
EventInfo evClick = tExForm.GetEvent("Click");
Type tDelegate = evClick.EventHandlerType;

// If you already have a method with the correct signature,
// you can simply get a MethodInfo for it.
//
MethodInfo miHandler =
typeof(Example).GetMethod("LuckyHandler",
BindingFlags.NonPublic | BindingFlags.Instance);
// Create an instance of the delegate. Using the overloads
// of CreateDelegate that take MethodInfo is recommended.
//
Delegate d = Delegate.CreateDelegate(tDelegate, this, miHandler);

// Get the "add" accessor of the event and invoke it late-
// bound, passing in the delegate instance. This is equivalent
// to using the += operator in C#, or AddHandler in Visual
// Basic. The instance on which the "add" accessor is invoked
// is the form; the arguments must be passed as an array.
//
MethodInfo addHandler = evClick.GetAddMethod();
Object[] addHandlerArgs = { d };
addHandler.Invoke(exFormAsObj, addHandlerArgs);

// Event handler methods can also be generated at run time,
// using lightweight dynamic methods and Reflection.Emit.
// To construct an event handler, you need the return type
// and parameter types of the delegate. These can be obtained
// by examining the delegate's Invoke method.
//
// It is not necessary to name dynamic methods, so the empty
// string can be used. The last argument associates the
// dynamic method with the current type, giving the delegate
// access to all the public and private members of Example,
// as if it were an instance method.
//
Type returnType = GetDelegateReturnType(tDelegate);
if (returnType != typeof(void))
throw new ApplicationException("Delegate has a return type.");

DynamicMethod handler =
new DynamicMethod("",
null,
GetDelegateParameterTypes(tDelegate),
typeof(Example));

// Generate a method body. This method loads a string, calls
// the Show method overload that takes a string, pops the
// return value off the stack (because the handler has no
// return type), and returns.
//
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);

// Complete the dynamic method by calling its CreateDelegate
// method. Use the "add" accessor to add the delegate to
// the invocation list for the event.
//
Delegate dEmitted = handler.CreateDelegate(tDelegate);
addHandler.Invoke(exFormAsObj, new Object[] { dEmitted });

// Show the form. Clicking on the form causes the two
// delegates to be invoked.
//
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 ApplicationException("Not a delegate.");

MethodInfo invoke = d.GetMethod("Invoke");
if (invoke == null)
throw new ApplicationException("Not a delegate.");

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 ApplicationException("Not a delegate.");

MethodInfo invoke = d.GetMethod("Invoke");
if (invoke == null)
throw new ApplicationException("Not a delegate.");

return invoke.ReturnType;
}
}

此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。