惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Project Zero
Project Zero
WordPress大学
WordPress大学
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
V
Visual Studio Blog
爱范儿
爱范儿
P
Proofpoint News Feed
F
Fortinet All Blogs
雷峰网
雷峰网
小众软件
小众软件
Jina AI
Jina AI
人人都是产品经理
人人都是产品经理
TaoSecurity Blog
TaoSecurity Blog
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
S
Secure Thoughts
Recent Commits to openclaw:main
Recent Commits to openclaw:main
博客园 - 司徒正美
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Microsoft Azure Blog
Microsoft Azure Blog
IT之家
IT之家
S
Security @ Cisco Blogs
Help Net Security
Help Net Security
GbyAI
GbyAI
Webroot Blog
Webroot Blog
T
Troy Hunt's Blog
B
Blog
MongoDB | Blog
MongoDB | Blog
月光博客
月光博客
H
Heimdal Security Blog
Google Online Security Blog
Google Online Security Blog
S
Security Affairs
云风的 BLOG
云风的 BLOG
Engineering at Meta
Engineering at Meta
www.infosecurity-magazine.com
www.infosecurity-magazine.com
H
Help Net Security
O
OpenAI News
H
Hacker News: Front Page
博客园 - 叶小钗
Last Week in AI
Last Week in AI
S
Schneier on Security
The Last Watchdog
The Last Watchdog
C
Cyber Attacks, Cyber Crime and Cyber Security
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
MyScale Blog
MyScale Blog
Recorded Future
Recorded Future
博客园 - 【当耐特】
V
Vulnerabilities – Threatpost
大猫的无限游戏
大猫的无限游戏
N
News | PayPal Newsroom
The Hacker News
The Hacker News
A
Arctic Wolf

博客园 - 小兔快跑

实现线程中的参数传递 利用rank() 和 dense_rank() 来实现分类排名 利用Relations实现多DataTable的聚合 Web应用中实现发送带附件的电子邮件 为什么这样的SQL会锁记录? 在Word里实现禁止复制和选定 [VS2005]解决“由于应用程序的配置不正确,应用程序未能启动,重新安装应用程序可能会纠正这个问题” Word转pdf方法小结 原来数据库编程也可以这么美好! ASP.NET生成WORD文档服务器部署注意事项 ASP.NET:页面保存为WORD出现的问题! 动态绑定图片url:数据绑定出现的问题 .NET对Excel的读写 .NET中的CString知识点 水滴石穿之页面遮罩层实现、向window.open()打开的窗口POST数据 动态加载和使用类型 WinForm 控件的事件委托剖析 SVG常见问题汇总 水滴石穿之子页面的滚动条设置 表格的固定高度宽度问题 复制带格式的文本
如何:使用反射将委托挂钩
小兔快跑 · 2008-04-27 · via 博客园 - 小兔快跑

如何:使用反射将委托挂钩

1. 加载包含引发事件的类型的程序集。程序集通常使用 Assembly.Load 方法加载。为了使此示例尽量简单,在当前程序集中使用了派生窗体,所以使用 GetExecutingAssembly 方法来加载当前程序集。

Assembly assem = Assembly.GetExecutingAssembly();


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

Type tExForm = assem.GetType("ExampleForm");
Object exFormAsObj 
= Activator.CreateInstance(tExForm);


3. 获取表示该事件的 EventInfo 对象,并使用 EventHandlerType 属性来获取用于处理事件的委托类型。在下面的代码中,获取了 Click 事件的 EventInfo。

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


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

MethodInfo miHandler = 
    
typeof(Example).GetMethod("LuckyHandler"
        BindingFlags.NonPublic 
| BindingFlags.Instance);


5. 使用 CreateDelegate 方法创建委托的实例。此方法是静态的(在 Visual Basic 中为 Shared),所以必须提供委托类型。建议使用带有 MethodInfo 的 CreateDelegate 重载。

Delegate d = Delegate.CreateDelegate(tDelegate, this, miHandler);


6. 获取 add 访问器方法,并调用该方法以将事件挂钩。所有事件都具有一个 add 访问器或 remove 访问器,这些访问器被高级语言的语法隐藏。例如,C# 使用 += 运算符将事件挂钩,而 Visual Basic 则使用 AddHandler 语句。下面的代码获取 Click 事件的 add 访问器并以后期绑定方式调用它,并在委托实例中传递。参数必须作为数组传递。

MethodInfo addHandler = evClick.GetAddMethod();
Object[] addHandlerArgs 
= { d };
addHandler.Invoke(exFormAsObj, addHandlerArgs);


7. 测试事件。下面的代码显示了在代码示例中定义的窗体。单击该窗体将调用事件处理程序。

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


2. 生成方法体。此方法加载字符串、调用带有字符串的 MessageBox.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);

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

}