返回首页


我曾参与在过去的几个星期,在此模块,并成功地完成了一个非常有创意的方式。好吧,这就是问题所在。我们有一个COM服务器,让我们将其命名为服务器。我不得不写在C#,让我们称之为桥,将侦听所有服务器开枪的事件,并执行行动对行动的大会。要记住,动作简单,让我们假设我们要在数据库中的日志。但服务器火灾数百项活动,是不明智写为所有这些静态的事件处理程序。此外,如果在将来添加更多的事件,它是可以支持的桥。
所以我想出了一个令人难以置信的反射不同的方法。NET中。所有服务器开枪的事件,它的原型及其他相关信息可以通过反射可以得到,并为每个事件的方法,一个事件接收器的事件处理程序]可在运行时产生的。这意味着我必须创建在运行时事件的原型匹配的一种方法。动态方法,从而在运行时产生的附加一些方法体,这样才能做的动作,然后将相应的事件的事件接收器注册。因此,当发射事件是由服务器,动态创建的事件处理程序被称为没有任何干预。这是我的解决方案的主题。这使桥服务器中的任何事件相关的变化的影响。
,但实现这一目标的解决方案,并使其工作是一个伟大的和令人兴奋的的冒险。我能够获得事件的信息服务器通过反射发射事件。我用下面的代码进行排序,生成动态方法或假想的动态事件处理程序:

using System;

using System.Threading;

using System.Reflection;

using System.Reflection.Emit;



class TaskDynamicEventHandler

{

    public static void CreateDynamicEventHandler(ref TypeBuilder myTypeBld,

                         string methodName,

                         Type[] eventMethodParameters,

                         Type eventreturnType)

    {

        MethodBuilder myMthdBld = myTypeBld.DefineMethod(methodName,

                          MethodAttributes.Public | MethodAttributes.Static,

                          eventreturnType,

                          eventMethodParameters);



        ILGenerator ILout = myMthdBld.GetILGenerator();



        int numParams = eventMethodParameters.Length;



        for (byte x = 0; x < numParams; x++)

        {

            // Load the parameter onto the evaluation stack

            ILout.Emit(OpCodes.Ldarg_S, x);

        }



        // Use the above sort of logic to access the event parameter

        // values and then package into a hashtable, and then call

        // a static method HandleEvent in TaskDynamicEventHandler,

        // which takes the hashtable as a parameter. All the code is 

        // generated in IL using ILGenerator.



        ILout.Emit(OpCodes.Ret);

    }



    public static void Main()

    {

        AppDomain myDomain = Thread.GetDomain();

        AssemblyName asmName = new AssemblyName("DynamicAssembly1");

        AssemblyBuilder myAsmBuilder = myDomain.DefineDynamicAssembly(asmName,

                       AssemblyBuilderAccess.RunAndSave);



        ModuleBuilder myModule = myAsmBuilder.DefineDynamicModule("DynamicModule1",

                                      "MyDynamicAsm.dll");



        TypeBuilder myTypeBld = myModule.DefineType("MyDynamicType",

                                       TypeAttributes.Public);



        string dynamicMethodName = "DynamicEventHandler";

        CreateDynamicEventHandler(myTypeBld,

                         dynamicMethodName,

                         eventMethodParameters,

                         eventreturnType);        



        Type myType = myTypeBld.CreateType();

        



        myAsmBuilder.Save("MyDynamicAsm.dll");

    }

}

这种方法的缺点是一个动态组装模块类型为每个事件创建的。这是不够有效,所以稍加改动的逻辑一旦创建动态组装的模块类型,并添加方法[动态事件处理程序]的动态类型。
虽然效率水平可能已经达到,这是不优雅,足够满意。动态事件处理程序[DEH]是一个特定的类型属于不同的大会,是在运行时产生的,这些DEH不属于相同大会TaskDynamicEventHandler类的所有方法。 DEHs的责任是看它的参数名称和值在运行时,它们打包成一个Hashtable和调用的TaskDynamicEventHandler方法的handleEvent,和它的handleEvent是日志记录的实际工作已经完成。那么,实际工作是不是只记录,但需要访问TaskDynamicEventHandler成员的其他东西。因此,非高雅这里的handleEvent作为公共静态方法,动态组装DEH可以调用,从而导致了丑陋的handleEvent被暴露到外面的世界大会,TaskDynamicEventHandler属于暴露。所以的handleEvent不能非公有制。但它是其他原因需要是一个实例方法。这里是最有趣的部分。目的是使对DEH TaskDynamicEventHandler即的handleEvent调用实例方法。你如何使一个静态方法调用实例方法呢?好吧,如果我有一个在执行对DEH TaskDynamicEventHandler类对象的引用,如果我能加载到计算堆栈[使用IL代码/ ILGenerator],然后我调用一个实例方法。这是痛苦,这是非常棘手的和有趣的谁我解释,大家都不能正确地把握"本"在编译的代码中使用,不会在运行时对DEH IL代码相同,我也不能负荷无我创造它或作为参数的对象的引用。这是所有的。NET类型的安全性。你不会得到任何机会做reinterpret_cast类的东西。但是你可以通过对DEH TaskDynamicEventHandler对象参考[本],但比对DEH的原型不匹配,其相应的事件原型,因此不能作为一个接收器的目标。NET 2.0中来在一定程度上的救援,并帮助我们实现的目标 - 。效率和优雅。有一个类名动态方法来动态创建方法。美丽的动态方法是,它是当前类TaskDynamicEventHandler的成员可以添加动态方法。{C}
,因此对DEH现在是相同的程序集和类的一部分,它甚至可以调用非公共方法。效率很好地实现,但仍然优雅是几英尺远。创建并添加到TaskDynamicEventHandler使用DynamicMethod类的动态方法是一个静态方法,因此不能访问TaskDynamicEventHandler的实例方法,虽然它可以访问非公共方法。这里是最有趣的部分。本次迭代的目的是使对DEH TaskDynamicEventHandler即的handleEvent调用实例方法。你如何使一个静态方法调用实例方法呢?好吧,如果我有一个在执行对DEH TaskDynamicEventHandler类对象的引用,如果我能加载到计算堆栈[使用IL代码/ ILGenerator],然后我调用一个实例方法。事情变得有趣了。一个实例和静态方法之间的区别是,一个实例方法,作为第一个参数的对象的引用,它所属的,而一个静态方法不。虽然语法,对象引用不添加,编译器会将它。因此,尽管创建动态方法[DEH]事件,TaskDynamicEventHandler对象引用[]作为第一个参数到事件参数列表。这使得对DEH似乎是一个实例方法。因此,在运行时,触发事件时,其相应的DEH执行IL代码Lgarg_0代表它所属的对象的引用,它是为的handleEvent相同。 但即使是现在的handleEvent是公众和易受不当使用。我做了一个虚拟的方法。这是有趣的,和现在完全是用户的责任,以避免不当使用,它高达用户覆盖的handleEvent为所欲为。用于调试的IL代码中的一些次要的东西增值Trace.WriteLine使用ILGenerator;添加的try - catch捕获异常的异常块,但遗憾的是似乎并没有工作。
所有这些方法,直到最后的效率和优雅的解决方案多次迭代,重新审视和检讨。我将无法解释有关的困难和严峻的IL调试经验,我通过尝试虚拟实例的方法,使的handleEvent,虽然我将能够分享喜悦和知识。这是一个伟大的经验!

回答

评论会员:cs_dilo 时间:2012/01/26
不够清楚这个网站,太自我放纵
评论会员:。cmschick 时间:2012/01/26
通常情况下,我讨厌当人们给低票上的文章。这主要是因为,我认为最谁做可能不会有任何物品,贡献自己。然而,在这种情况下,在阅读文章后我真的倾向于同意这一表决。这是完全不清楚有什么解决办法解决或它是如何可重复使用。这当然不是一个"大汇演",并在那里有很多自我放纵