使用反射将委托挂钩

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Reflection;
using System.Reflection.Emit;

namespace EmitHandler
{
    public class Example
    {
        /// <summary>
        /// 使用反射将委托挂钩
        /// </summary>
        /// <param name="outputBlock"></param>
        public static void Demo(System.Windows.Controls.TextBlock outputBlock)
        {
            // 获取某一未知对象,或者创建在您已加载的程序集中找到的类型的对象。
            // 为使示例简单,使用的对象是为示例的输出提供的 TextBlock;
            // 但是,TextBlock 存储为 Object 类型,以保持对该对象或其来自的程序集一无所知的状态
            object obj = outputBlock;

            // 获取表示该事件的 EventInfo 对象,并使用 EventHandlerType 属性来获取用于处理事件的委托类型。
            // 在下面的代码中,获取了 MouseLeftButtonUp 事件的 EventInfo。
            // 此示例按名称查找事件,但可以使用 Type.GetEvents 方法来查看存在哪些事件
            //foreach(EventInfo ei in outputBlock.GetType().GetEvents())
            //{
            //    outputBlock.Text += ei.Name+"\n";
            //}

            //Type opb = typeof(TextBlock);

            //foreach (MethodInfo ei in opb.GetMethods())
            //{
            //    //if (ei.Name.StartsWith("g"))
            //    outputBlock.Text += ei.Name + "\n";
            //}

 


            EventInfo evMouseUp = outputBlock.GetType().GetEvent("MouseLeftButtonUp");
            Type tEenType = evMouseUp.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.Static);
           
            // 创建委托实例.
           
            Delegate d = Delegate.CreateDelegate(tEenType, miHandler);

            //获取 add 访问器方法,并调用该方法以将事件挂钩。
            //所有事件都具有一个 add 访问器或 remove 访问器,这些访问器被高级语言的语法隐藏。
            //例如,C# 使用 += 运算符将事件挂钩,而 Visual Basic 则使用 AddHandler 语句。
            //下面的代码获取 MouseLeftButtonUp 事件的 add 访问器并以后期绑定方式调用它,并在委托实例中传递。
            //参数必须作为数组传递
            MethodInfo miAddHandler = evMouseUp.GetAddMethod();
            object[] addHandlerArgs = { d };
            miAddHandler.Invoke(obj, addHandlerArgs);
            //outputBlock.Text += "Click here to invoke the two delegates.\n";


            // 使用轻量动态方法和反射发出可在运行时生成事件处理程序方法。
            // 若要构造事件处理程序,您需要知道返回类型和委托的参数类型。
            // 可以通过检查委托的 Invoke 方法来获取这些类型。下
            // 面的代码使用 GetDelegateReturnType 和 GetDelegateParameterTypes 方法通过反射获取此信息。
           
            Type returnType = GetDelegateReturnType(tEenType);
            if (returnType != typeof(void))
            {
                throw new InvalidOperationException("Delegate has a return type.");
            }

            DynamicMethod handler =
               new DynamicMethod("", null, GetDelegateParameterTypes(tEenType));

            // 生成方法体。
            //此方法加载字符串、
            //调用带有单个字符串的 Show 方法重载、
            //从堆栈弹出返回值(因为处理程序没有返回类型)并返回这些值.
            ILGenerator ilgen = handler.GetILGenerator();

            Type[] showParameters = { typeof(string) };
            MethodInfo miShow =
               typeof(System.Windows.MessageBox).GetMethod("Show", showParameters);

            //推送对元数据中存储的字符串的新对象引用
            ilgen.Emit(OpCodes.Ldstr, "This event handler was constructed at run time.");
            //调用方法
            ilgen.Emit(OpCodes.Call, miShow);
            //出栈
            ilgen.Emit(OpCodes.Pop);
            //返回
            ilgen.Emit(OpCodes.Ret);


            Delegate dEmitted = handler.CreateDelegate(tEenType);
            evMouseUp.AddEventHandler(obj, dEmitted);

            // Clicking on the TextBlock now causes the two delegates to
            // be invoked.
            //
            outputBlock.Text += "Click here to invoke the two delegates.\n";
        }

        private static void LuckyHandler(object sender, EventArgs e)
        {
            System.Windows.MessageBox.Show(
               "This event handler just happened to be lying around.");
        }

        private static Type[] GetDelegateParameterTypes(Type d)
        {
            if (d.BaseType != typeof(MulticastDelegate))
            {
                throw new InvalidOperationException("Not a delegate.");
            }

            MethodInfo invoke = d.GetMethod("Invoke");
            if (invoke == null)
            {
                throw new InvalidOperationException("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 static Type GetDelegateReturnType(Type d)
        {
            if (d.BaseType != typeof(MulticastDelegate))
            {
                throw new InvalidOperationException("Not a delegate.");
            }

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

            return invoke.ReturnType;
        }

    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值