zoukankan      html  css  js  c++  java
  • 使用反射将委托挂钩

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

        }
    }

    关于作者: 王昕(QQ:475660) 在广州工作生活30余年。十多年开发经验,在Java、即时通讯、NoSQL、BPM、大数据等领域较有经验。
    目前维护的开源产品:https://gitee.com/475660
  • 相关阅读:
    WCF服务自我寄宿 Windows服务
    客户端调用 WCF 的几种方式
    SQL Server 2005 数据库 可疑状态
    mysql server 自动断开的问题
    mysql数据表简单拷贝及重命名
    Mac提示App已损坏 你应该将它移到废纸篓的解决方案
    Mac系统下安装Tomcat,以及终端出现No such file or directory的错误提示解决方案
    md1
    转-SourceTree注册atlassian账号SIGUP按钮灰色无法注册的问题
    mysql my.cnf优化
  • 原文地址:https://www.cnblogs.com/starcrm/p/1519246.html
Copyright © 2011-2022 走看看