Esempio n. 1
0
        /// <summary>
        /// Parses IML and build a dynamic method that will be used to instanciate one or multiple occurence of the IML file or fragment
        /// </summary>
        void parseIML(XmlTextReader reader)
        {
            Context ctx = new Context (findRootType (reader));

            ctx.nodesStack.Push (new Node (ctx.RootType));
            emitLoader (reader, ctx);
            ctx.nodesStack.Pop ();

            foreach (int idx in templateCachedDelegateIndices)
                ctx.emitCachedDelegateHandlerAddition(idx, CompilerServices.eiLogicalParentChanged);

            ctx.ResolveNamedTargets ();

            emitBindingDelegates (ctx);

            ctx.il.Emit (OpCodes.Ldloc_0);//load root obj to return
            ctx.il.Emit(OpCodes.Ret);

            reader.Read ();//close tag
            RootType = ctx.RootType;
            loader = (InstanciatorInvoker)ctx.dm.CreateDelegate (typeof (InstanciatorInvoker), this);
        }
Esempio n. 2
0
        void emitTemplateBindings(Context ctx, Dictionary<string, List<MemberAddress>> bindings)
        {
            //value changed dyn method
            DynamicMethod dm = new DynamicMethod ("dyn_tmpValueChanged",
                typeof (void), CompilerServices.argsValueChange, true);
            ILGenerator il = dm.GetILGenerator (256);

            //create parentchanged dyn meth in parallel to have only one loop over bindings
            DynamicMethod dmPC = new DynamicMethod ("dyn_InitAndLogicalParentChanged",
                typeof (void),
                CompilerServices.argsBoundDSChange, true);
            ILGenerator ilPC = dmPC.GetILGenerator (256);

            il.Emit (OpCodes.Nop);
            ilPC.Emit (OpCodes.Nop);

            System.Reflection.Emit.Label endMethod = il.DefineLabel ();

            il.DeclareLocal (CompilerServices.TObject);
            ilPC.DeclareLocal (CompilerServices.TObject);//used for checking propery less bindings
            ilPC.DeclareLocal (typeof(MemberInfo));//used for checking propery less bindings

            System.Reflection.Emit.Label cancel = ilPC.DefineLabel ();

            #region Unregister previous parent event handler
            //unregister previous parent handler if not null
            ilPC.Emit (OpCodes.Ldarg_2);//load old parent
            ilPC.Emit (OpCodes.Ldfld, CompilerServices.fiDSCOldDS);
            ilPC.Emit (OpCodes.Brfalse, cancel);//old parent is null

            ilPC.Emit (OpCodes.Ldarg_2);//load old parent
            ilPC.Emit (OpCodes.Ldfld, CompilerServices.fiDSCOldDS);
            //Load cached delegate
            ilPC.Emit(OpCodes.Ldarg_0);//load ref to this instanciator onto the stack
            ilPC.Emit(OpCodes.Ldfld, CompilerServices.fiTemplateBinding);

            //add template bindings dynValueChanged delegate to new parent event
            ilPC.Emit(OpCodes.Callvirt, CompilerServices.eiValueChange.RemoveMethod);//call remove event
            #endregion

            ilPC.MarkLabel(cancel);

            #region check if new parent is null
            cancel = ilPC.DefineLabel ();
            ilPC.Emit (OpCodes.Ldarg_2);//load datasource change arg
            ilPC.Emit (OpCodes.Ldfld, CompilerServices.fiDSCNewDS);
            ilPC.Emit (OpCodes.Brfalse, cancel);//new ds is null
            #endregion

            int i = 0;
            foreach (KeyValuePair<string, List<MemberAddress>> bindingCase in bindings ) {

                System.Reflection.Emit.Label nextTest = il.DefineLabel ();

                #region member name test
                //load source member name
                il.Emit (OpCodes.Ldarg_1);
                il.Emit (OpCodes.Ldfld, CompilerServices.fiVCMbName);

                il.Emit (OpCodes.Ldstr, bindingCase.Key);//load name to test
                il.Emit (OpCodes.Ldc_I4_4);//StringComparison.Ordinal
                il.Emit (OpCodes.Callvirt, CompilerServices.stringEquals);
                il.Emit (OpCodes.Brfalse, nextTest);//if not equal, jump to next case
                #endregion

                #region destination member affectations

                foreach (MemberAddress ma in bindingCase.Value) {
                    if (ma.Address.Count == 0){
                        Debug.WriteLine("\t\tBUG: reverse template binding in normal template binding");
                        continue;//template binding
                    }
                    //first we try to get memberInfo of new parent, if it doesn't exist, it's a propery less binding
                    ilPC.Emit (OpCodes.Ldarg_2);//load new parent onto the stack for handler addition
                    ilPC.Emit (OpCodes.Ldfld, CompilerServices.fiDSCNewDS);
                    ilPC.Emit (OpCodes.Stloc_0);//save new parent
                    //get parent type
                    ilPC.Emit (OpCodes.Ldloc_0);//push parent instance
                    ilPC.Emit (OpCodes.Ldstr, bindingCase.Key);//load member name
                    ilPC.Emit (OpCodes.Call, CompilerServices.miGetMembIinfoWithRefx);
                    ilPC.Emit (OpCodes.Stloc_1);//save memberInfo
                    ilPC.Emit (OpCodes.Ldloc_1);//push mi for test if null
                    System.Reflection.Emit.Label propLessReturn = ilPC.DefineLabel ();
                    ilPC.Emit (OpCodes.Brfalse, propLessReturn);

                    //first we have to load destination instance onto the stack, it is access
                    //with graphic tree functions deducted from nodes topology
                    il.Emit (OpCodes.Ldarg_0);//load source instance of ValueChanged event
                    CompilerServices.emitGetChild (il, typeof(TemplatedControl), -1);
                    CompilerServices.emitGetInstance (il, ma.Address);

                    ilPC.Emit (OpCodes.Ldarg_2);//load destination instance to set actual value of member
                    ilPC.Emit (OpCodes.Ldfld, CompilerServices.fiDSCNewDS);
                    CompilerServices.emitGetChild (ilPC, typeof(TemplatedControl), -1);
                    CompilerServices.emitGetInstance (ilPC, ma.Address);

                    //load new value
                    il.Emit (OpCodes.Ldarg_1);
                    il.Emit (OpCodes.Ldfld, CompilerServices.fiVCNewValue);

                    //for the parent changed dyn meth we need to fetch actual value for initialisation thrue reflexion
                    ilPC.Emit (OpCodes.Ldloc_0);//push root instance of instanciator as parentChanged source
                    ilPC.Emit (OpCodes.Ldloc_1);//push mi for value fetching
                    ilPC.Emit (OpCodes.Call, CompilerServices.miGetValWithRefx);

                    CompilerServices.emitConvert (il, ma.Property.PropertyType);
                    CompilerServices.emitConvert (ilPC, ma.Property.PropertyType);

                    il.Emit (OpCodes.Callvirt, ma.Property.GetSetMethod());
                    ilPC.Emit (OpCodes.Callvirt, ma.Property.GetSetMethod());

                    ilPC.MarkLabel(propLessReturn);
                }
                #endregion
                il.Emit (OpCodes.Br, endMethod);
                il.MarkLabel (nextTest);

                i++;
            }
            //il.Emit (OpCodes.Pop);
            il.MarkLabel (endMethod);
            il.Emit (OpCodes.Ret);

            //store template bindings in instanciator
            templateBinding = dm.CreateDelegate (typeof(EventHandler<ValueChangeEventArgs>));

            #region emit LogicalParentChanged method

            //load new parent onto the stack for handler addition
            ilPC.Emit (OpCodes.Ldarg_2);
            ilPC.Emit (OpCodes.Ldfld, CompilerServices.fiDSCNewDS);

            //Load cached delegate
            ilPC.Emit(OpCodes.Ldarg_0);//load ref to this instanciator onto the stack
            ilPC.Emit(OpCodes.Ldfld, CompilerServices.fiTemplateBinding);

            //add template bindings dynValueChanged delegate to new parent event
            ilPC.Emit(OpCodes.Callvirt, CompilerServices.eiValueChange.AddMethod);//call add event

            ilPC.MarkLabel (cancel);
            ilPC.Emit (OpCodes.Ret);

            //store dschange delegate in instatiator instance for access while instancing graphic object
            int delDSIndex = cachedDelegates.Count;
            cachedDelegates.Add(dmPC.CreateDelegate (CompilerServices.ehTypeDSChange, this));
            #endregion

            ctx.emitCachedDelegateHandlerAddition(delDSIndex, CompilerServices.eiLogicalParentChanged);
        }
Esempio n. 3
0
        void emitPropertyBindings(Context ctx, NodeAddress origine, Dictionary<string, List<MemberAddress>> bindings)
        {
            Type origineNodeType = origine.NodeType;

            //value changed dyn method
            DynamicMethod dm = new DynamicMethod ("dyn_valueChanged" + NewId,
                typeof (void), CompilerServices.argsValueChange, true);
            ILGenerator il = dm.GetILGenerator (256);

            System.Reflection.Emit.Label endMethod = il.DefineLabel ();

            il.DeclareLocal (CompilerServices.TObject);

            il.Emit (OpCodes.Nop);

            int i = 0;
            foreach (KeyValuePair<string, List<MemberAddress>> bindingCase in bindings ) {

                System.Reflection.Emit.Label nextTest = il.DefineLabel ();

                #region member name test
                //load source member name
                il.Emit (OpCodes.Ldarg_1);
                il.Emit (OpCodes.Ldfld, CompilerServices.fiVCMbName);

                il.Emit (OpCodes.Ldstr, bindingCase.Key);//load name to test
                il.Emit (OpCodes.Ldc_I4_4);//StringComparison.Ordinal
                il.Emit (OpCodes.Callvirt, CompilerServices.stringEquals);
                il.Emit (OpCodes.Brfalse, nextTest);//if not equal, jump to next case
                #endregion

                #region destination member affectations
                PropertyInfo piOrig = origineNodeType.GetProperty (bindingCase.Key);
                Type origineType = null;
                if (piOrig != null)
                    origineType = piOrig.PropertyType;
                foreach (MemberAddress ma in bindingCase.Value) {
                    //first we have to load destination instance onto the stack, it is access
                    //with graphic tree functions deducted from nodes topology
                    il.Emit (OpCodes.Ldarg_0);//load source instance of ValueChanged event

                    NodeAddress destination = ma.Address;

                    if (destination.Count == 0){//template reverse binding
                        //fetch destination instance (which is the template root)
                        for (int j = 0; j < origine.Count ; j++)
                            il.Emit(OpCodes.Callvirt, CompilerServices.miGetLogicalParent);
                    }else
                        CompilerServices.emitGetInstance (il, origine, destination);

                    if (origineType != null && destination.Count > 0){//else, prop less binding or reverse template bind, no init requiered
                        //for initialisation dynmeth, push destination instance loc_0 is root node in ctx
                        ctx.il.Emit(OpCodes.Ldloc_0);
                        CompilerServices.emitGetInstance (ctx.il, destination);

                        //init dynmeth: load actual value from origine
                        ctx.il.Emit (OpCodes.Ldloc_0);
                        CompilerServices.emitGetInstance (ctx.il, origine);
                        ctx.il.Emit (OpCodes.Callvirt, origineNodeType.GetProperty (bindingCase.Key).GetGetMethod());
                    }
                    //load new value
                    il.Emit (OpCodes.Ldarg_1);
                    il.Emit (OpCodes.Ldfld, CompilerServices.fiVCNewValue);

                    if (origineType == null)//property less binding, no init
                        CompilerServices.emitConvert (il, ma.Property.PropertyType);
                    else if (destination.Count > 0) {
                        if (origineType.IsValueType)
                            ctx.il.Emit(OpCodes.Box, origineType);

                        CompilerServices.emitConvert (ctx.il, origineType, ma.Property.PropertyType);
                        CompilerServices.emitConvert (il, origineType, ma.Property.PropertyType);

                        ctx.il.Emit (OpCodes.Callvirt, ma.Property.GetSetMethod());//set init value
                    } else {// reverse templateBinding
                        il.Emit (OpCodes.Ldstr, ma.memberName);//arg 3 of setValueWithReflexion
                        il.Emit (OpCodes.Call, CompilerServices.miSetValWithRefx);
                        continue;
                    }
                    il.Emit (OpCodes.Callvirt, ma.Property.GetSetMethod());//set value on value changes
                }
                #endregion
                il.Emit (OpCodes.Br, endMethod);
                il.MarkLabel (nextTest);

                i++;
            }

            il.MarkLabel (endMethod);
            il.Emit (OpCodes.Ret);

            //store and emit Add in ctx
            int dmIdx = cachedDelegates.Count;
            cachedDelegates.Add (dm.CreateDelegate (typeof(EventHandler<ValueChangeEventArgs>)));
            ctx.emitCachedDelegateHandlerAddition (dmIdx, CompilerServices.eiValueChange, origine);
        }
Esempio n. 4
0
        /// <summary> Emits handler method bindings </summary>
        void emitHandlerBinding(Context ctx, EventInfo sourceEvent, string expression)
        {
            NodeAddress currentNode = ctx.CurrentNodeAddress;
            BindingDefinition bindingDef = splitBindingExp (currentNode, sourceEvent.Name, expression);

            #if DEBUG_BINDING
            Debug.WriteLine("Event Binding: " + bindingDef.ToString());
            #endif

            if (bindingDef.IsTemplateBinding | bindingDef.IsDataSourceBinding) {
                //we need to bind datasource method to source event
                DynamicMethod dm = new DynamicMethod ("dyn_dschangedForHandler" + NewId,
                                       typeof(void),
                                       CompilerServices.argsBoundDSChange, true);

                ILGenerator il = dm.GetILGenerator (256);
                System.Reflection.Emit.Label cancel = il.DefineLabel ();

                il.DeclareLocal (typeof(MethodInfo));//used to cancel binding if method doesn't exist

                il.Emit (OpCodes.Nop);

                emitRemoveOldDataSourceHandler (il, sourceEvent.Name, bindingDef.TargetMember, false);

                //fetch method in datasource and test if it exist
                il.Emit (OpCodes.Ldarg_2);//load new datasource
                il.Emit (OpCodes.Ldfld, CompilerServices.fiDSCNewDS);
                il.Emit (OpCodes.Brfalse, cancel);//cancel if new datasource is null
                il.Emit (OpCodes.Ldarg_2);//load new datasource
                il.Emit (OpCodes.Ldfld, CompilerServices.fiDSCNewDS);
                il.Emit (OpCodes.Ldstr, bindingDef.TargetMember);//load handler method name
                il.Emit (OpCodes.Call, CompilerServices.miGetMethInfoWithRefx);
                il.Emit (OpCodes.Stloc_0);//save MethodInfo
                il.Emit (OpCodes.Ldloc_0);//push mi for test if null

                il.Emit (OpCodes.Brfalse, cancel);

                il.Emit (OpCodes.Ldarg_1);//load datasource change source where the event is as 1st arg of handler.add
                if (bindingDef.IsTemplateBinding)//fetch source instance with address
                    CompilerServices.emitGetInstance (il, bindingDef.SourceNA);

                //load handlerType of sourceEvent to create delegate (1st arg)
                il.Emit (OpCodes.Ldtoken, sourceEvent.EventHandlerType);
                il.Emit (OpCodes.Call, CompilerServices.miGetTypeFromHandle);
                il.Emit (OpCodes.Ldarg_2);//load new datasource where the method is defined
                il.Emit (OpCodes.Ldfld, CompilerServices.fiDSCNewDS);
                il.Emit (OpCodes.Ldloc_0);//load methodInfo (3rd arg)

                il.Emit (OpCodes.Callvirt, CompilerServices.miCreateBoundDel);
                il.Emit (OpCodes.Callvirt, sourceEvent.AddMethod);//call add event

                System.Reflection.Emit.Label finish = il.DefineLabel ();
                il.Emit (OpCodes.Br, finish);
                il.MarkLabel (cancel);
                il.EmitWriteLine (string.Format ("Handler method '{0}' for '{1}' not found in new dataSource ", bindingDef.TargetMember, sourceEvent.Name));
                il.MarkLabel (finish);
                il.Emit (OpCodes.Ret);

                //store dschange delegate in instatiator instance for access while instancing graphic object
                int delDSIndex = cachedDelegates.Count;
                cachedDelegates.Add (dm.CreateDelegate (CompilerServices.ehTypeDSChange, this));

                if (bindingDef.IsDataSourceBinding)
                    ctx.emitCachedDelegateHandlerAddition (delDSIndex, CompilerServices.eiDSChange);
                else //template handler binding, will be added to root parentChanged
                    templateCachedDelegateIndices.Add (delDSIndex);
            } else {//normal in tree handler binding, store until tree is complete (end of parse)
                ctx.UnresolvedTargets.Add (new EventBinding (
                    bindingDef.SourceNA, sourceEvent,
                    bindingDef.TargetNA, bindingDef.TargetMember, bindingDef.TargetName));
            }
        }
Esempio n. 5
0
        /// <summary>
        /// create the valuechanged handler, the datasourcechanged handler and emit event handling
        /// </summary>
        void emitDataSourceBindings(Context ctx, BindingDefinition bindingDef)
        {
            DynamicMethod dm = null;
            ILGenerator il = null;
            int dmVC = 0;
            PropertyInfo piSource = ctx.CurrentNodeType.GetProperty(bindingDef.SourceMember);
            //if no dataSource member name is provided, valuechange is not handle and datasource change
            //will be used as origine value
            string delName = "dyn_DSvalueChanged" + NewId;
            if (!string.IsNullOrEmpty(bindingDef.TargetMember)){
                #region create valuechanged method
                dm = new DynamicMethod (delName,
                    typeof (void),
                    CompilerServices.argsBoundValueChange, true);

                il = dm.GetILGenerator (256);

                System.Reflection.Emit.Label endMethod = il.DefineLabel ();

                il.DeclareLocal (CompilerServices.TObject);

                il.Emit (OpCodes.Nop);

                //load value changed member name onto the stack
                il.Emit (OpCodes.Ldarg_2);
                il.Emit (OpCodes.Ldfld, CompilerServices.fiVCMbName);

                //test if it's the expected one
                il.Emit (OpCodes.Ldstr, bindingDef.TargetMember);
                il.Emit (OpCodes.Ldc_I4_4);//StringComparison.Ordinal
                il.Emit (OpCodes.Callvirt, CompilerServices.stringEquals);
                il.Emit (OpCodes.Brfalse, endMethod);
                //set destination member with valueChanged new value
                //load destination ref
                il.Emit (OpCodes.Ldarg_0);
                //load new value onto the stack
                il.Emit (OpCodes.Ldarg_2);
                il.Emit (OpCodes.Ldfld, CompilerServices.fiVCNewValue);

                //by default, source value type is deducted from target member type to allow
                //memberless binding, if targetMember exists, it will be used to determine target
                //value type for conversion

                CompilerServices.emitConvert (il, piSource.PropertyType);

                il.Emit (OpCodes.Callvirt, piSource.GetSetMethod ());

                il.MarkLabel (endMethod);
                il.Emit (OpCodes.Ret);

                //vc dyn meth is stored in a cached list, it will be bound to datasource only
                //when datasource of source graphic object changed
                dmVC = dsValueChangedDynMeths.Count;
                dsValueChangedDynMeths.Add (dm);
                #endregion
            }

            #region emit dataSourceChanged event handler
            //now we create the datasource changed method that will init the destination member with
            //the actual value of the origin member of the datasource and then will bind the value changed
            //dyn methode.
            //dm is bound to the instanciator instance to have access to cached dyn meth and delegates
            dm = new DynamicMethod ("dyn_dschanged",
                typeof (void),
                CompilerServices.argsBoundDSChange, true);

            il = dm.GetILGenerator (256);

            il.DeclareLocal (CompilerServices.TObject);//used for checking propery less bindings
            il.DeclareLocal (typeof(MemberInfo));//used for checking propery less bindings
            System.Reflection.Emit.Label cancel = il.DefineLabel ();
            System.Reflection.Emit.Label cancelInit = il.DefineLabel ();

            il.Emit (OpCodes.Nop);

            emitRemoveOldDataSourceHandler(il, "ValueChanged", delName);

            if (!string.IsNullOrEmpty(bindingDef.TargetMember)){
                if (bindingDef.TwoWay){
                    System.Reflection.Emit.Label cancelRemove = il.DefineLabel ();
                    //remove handler if not null
                    il.Emit (OpCodes.Ldarg_2);//load old parent
                    il.Emit (OpCodes.Ldfld, CompilerServices.fiDSCOldDS);
                    il.Emit (OpCodes.Brfalse, cancelRemove);//old parent is null

                    //remove handler
                    il.Emit (OpCodes.Ldarg_2);//1st arg load old datasource
                    il.Emit (OpCodes.Ldfld, CompilerServices.fiDSCOldDS);
                    il.Emit (OpCodes.Ldstr, "ValueChanged");//2nd arg event name
                    il.Emit (OpCodes.Ldarg_1);//3d arg: instance bound to delegate (the source)
                    il.Emit (OpCodes.Call, CompilerServices.miRemEvtHdlByTarget);
                    il.MarkLabel(cancelRemove);
                }
                il.Emit (OpCodes.Ldarg_2);//load datasource change arg
                il.Emit (OpCodes.Ldfld, CompilerServices.fiDSCNewDS);
                il.Emit (OpCodes.Brfalse, cancel);//new ds is null
            }

            #region fetch initial Value
            if (!string.IsNullOrEmpty(bindingDef.TargetMember)){
                il.Emit (OpCodes.Ldarg_2);//load new datasource
                il.Emit (OpCodes.Ldfld, CompilerServices.fiDSCNewDS);
                il.Emit (OpCodes.Ldstr, bindingDef.TargetMember);//load member name
                il.Emit (OpCodes.Call, CompilerServices.miGetMembIinfoWithRefx);
                il.Emit (OpCodes.Stloc_1);//save memberInfo
                il.Emit (OpCodes.Ldloc_1);//push mi for test if null
                il.Emit (OpCodes.Brfalse, cancelInit);//propertyLessBinding
            }

            il.Emit (OpCodes.Ldarg_1);//load source of dataSourceChanged which is the dest instance
            il.Emit (OpCodes.Ldarg_2);//load new datasource
            il.Emit (OpCodes.Ldfld, CompilerServices.fiDSCNewDS);
            if (!string.IsNullOrEmpty(bindingDef.TargetMember)){
                il.Emit (OpCodes.Ldloc_1);//push mi for value fetching
                il.Emit (OpCodes.Call, CompilerServices.miGetValWithRefx);
            }
            CompilerServices.emitConvert (il, piSource.PropertyType);
            il.Emit (OpCodes.Callvirt, piSource.GetSetMethod ());
            #endregion

            if (!string.IsNullOrEmpty(bindingDef.TargetMember)){
                il.MarkLabel(cancelInit);
                //check if new dataSource implement IValueChange
                il.Emit (OpCodes.Ldarg_2);//load new datasource
                il.Emit (OpCodes.Ldfld, CompilerServices.fiDSCNewDS);
                il.Emit (OpCodes.Isinst, typeof(IValueChange));
                il.Emit (OpCodes.Brfalse, cancel);

                il.Emit(OpCodes.Ldarg_0);//load ref to this instanciator onto the stack
                il.Emit (OpCodes.Ldarg_1);//load datasource change source
                il.Emit (OpCodes.Ldarg_2);//load new datasource
                il.Emit (OpCodes.Ldfld, CompilerServices.fiDSCNewDS);
                il.Emit(OpCodes.Ldc_I4, dmVC);//load index of dynmathod
                il.Emit (OpCodes.Call, CompilerServices.miDSChangeEmitHelper);

                if (bindingDef.TwoWay){
                    il.Emit (OpCodes.Ldarg_1);//arg1: dataSourceChange source, the origine of the binding
                    il.Emit (OpCodes.Ldstr, bindingDef.SourceMember);//arg2: orig member
                    il.Emit (OpCodes.Ldarg_2);//arg3: new datasource
                    il.Emit (OpCodes.Ldfld, CompilerServices.fiDSCNewDS);
                    il.Emit (OpCodes.Ldstr, bindingDef.TargetMember);//arg4: dest member
                    il.Emit (OpCodes.Call, CompilerServices.miDSReverseBinding);
                }

                il.MarkLabel (cancel);
            }
            il.Emit (OpCodes.Ret);

            //store dschange delegate in instatiator instance for access while instancing graphic object
            int delDSIndex = cachedDelegates.Count;
            cachedDelegates.Add(dm.CreateDelegate (CompilerServices.ehTypeDSChange, this));
            #endregion

            ctx.emitCachedDelegateHandlerAddition(delDSIndex, CompilerServices.eiDSChange);
        }
Esempio n. 6
0
 /// <summary>
 /// Compile events expression in IML attributes, and store the result in the instanciator
 /// Those handlers will be bound when instatiing
 /// </summary>
 void compileAndStoreDynHandler(Context ctx, EventInfo sourceEvent, string expression)
 {
     //store event handler dynamic method in instanciator
     int dmIdx = cachedDelegates.Count;
     cachedDelegates.Add (CompilerServices.compileDynEventHandler (sourceEvent, expression, ctx.CurrentNodeAddress));
     ctx.emitCachedDelegateHandlerAddition(dmIdx, sourceEvent);
 }