反射绑定事件

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

 

posted @ 2021-12-17 15:37  灰色淡季  阅读(26)  评论(0)    收藏  举报