Пример #1
0
        /// <summary>
        /// check type of current object on the stack and convert to dest type,
        /// use loc_0 so store it as object!!!
        /// </summary>
        internal static void emitConvert(ILGenerator il, Type dstType)
        {
            System.Reflection.Emit.Label endConvert = il.DefineLabel();
            System.Reflection.Emit.Label convert    = il.DefineLabel();

            il.Emit(OpCodes.Dup);
            il.Emit(OpCodes.Isinst, dstType);
            il.Emit(OpCodes.Brfalse, convert);

            if (dstType.IsValueType)
            {
                il.Emit(OpCodes.Unbox_Any, dstType);
            }
            else
            {
                il.Emit(OpCodes.Isinst, dstType);
            }
            il.Emit(OpCodes.Br, endConvert);

            il.MarkLabel(convert);

            if (dstType == typeof(string))
            {
                System.Reflection.Emit.Label emitNullStr = il.DefineLabel();
                il.Emit(OpCodes.Dup);
                il.Emit(OpCodes.Brfalse, emitNullStr);
                il.Emit(OpCodes.Callvirt, CompilerServices.miObjToString);
                il.Emit(OpCodes.Br, endConvert);
                il.MarkLabel(emitNullStr);
                il.Emit(OpCodes.Pop);                 //remove null string from stack
                il.Emit(OpCodes.Ldstr, "");           //replace with empty string
            }
            else if (dstType.IsPrimitive)
            {
                //il.Emit (OpCodes.Unbox_Any, dstType);
                il.Emit(OpCodes.Callvirt, CompilerServices.GetConvertMethod(dstType));
            }
            else if (dstType.IsValueType)
            {
                il.Emit(OpCodes.Unbox_Any, dstType);
            }
            else
            {
                il.Emit(OpCodes.Stloc_0);                  //save orig value in loc0
                //first check if not null
                il.Emit(OpCodes.Ldloc_0);
                il.Emit(OpCodes.Dup);
                il.Emit(OpCodes.Brfalse, endConvert);
                il.Emit(OpCodes.Callvirt, miGetType);
                il.Emit(OpCodes.Ldtoken, dstType);                 //push destination property type for testing
                il.Emit(OpCodes.Call, CompilerServices.miGetTypeFromHandle);
                il.Emit(OpCodes.Call, miGetImplOp);
                il.Emit(OpCodes.Dup);
                convert = il.DefineLabel();
                il.Emit(OpCodes.Brtrue, convert);
                il.Emit(OpCodes.Pop);
                il.Emit(OpCodes.Ldloc_0);
                il.Emit(OpCodes.Isinst, dstType);
                il.Emit(OpCodes.Br, endConvert);

                il.MarkLabel(convert);
                il.Emit(OpCodes.Ldnull);                 //null instance for invoke
                il.Emit(OpCodes.Ldc_I4_1);
                il.Emit(OpCodes.Newarr, CompilerServices.TObject);
                il.Emit(OpCodes.Dup);                              //duplicate the array ref
                il.Emit(OpCodes.Ldc_I4_0);                         //push the index 0
                il.Emit(OpCodes.Ldloc_0);                          //push the orig value to convert
                il.Emit(OpCodes.Stelem, CompilerServices.TObject); //set the array element at index 0
                il.Emit(OpCodes.Callvirt, miMIInvoke);
            }

            il.MarkLabel(endConvert);
        }
Пример #2
0
        public static void ResolveBindings(List <Binding> Bindings)
        {
            if (Bindings == null)
            {
                return;
            }
            if (Bindings.Count == 0)
            {
                return;
            }
            //#if DEBUG_BINDING
            //			Debug.WriteLine ("Resolve Bindings => " + this.ToString ());
            //#endif
            //grouped bindings by Instance of Source
            Dictionary <object, List <Binding> > resolved = new Dictionary <object, List <Binding> > ();

            foreach (Binding b in Bindings)
            {
                if (b.Resolved)
                {
                    continue;
                }
                if (b.Source.Member.MemberType == MemberTypes.Event)
                {
                    if (b.Expression.StartsWith("{"))
                    {
                        CompilerServices.CompileEventSource(b);
                        continue;
                    }
                    if (!b.TryFindTarget())
                    {
                        continue;
                    }
                    //register handler for event
                    if (b.Target.Method == null)
                    {
                        Debug.WriteLine("\tError: Handler Method not found: " + b.ToString());
                        continue;
                    }
                    try {
                        MethodInfo addHandler = b.Source.Event.GetAddMethod();
                        Delegate   del        = Delegate.CreateDelegate(b.Source.Event.EventHandlerType, b.Target.Instance, b.Target.Method);
                        addHandler.Invoke(b.Source.Instance, new object [] { del });

#if DEBUG_BINDING
                        Debug.WriteLine("\tHandler binded => " + b.ToString());
#endif
                        b.Resolved = true;
                    } catch (Exception ex) {
                        Debug.WriteLine("\tERROR: " + ex.ToString());
                    }
                    continue;
                }

                if (!b.TryFindTarget())
                {
                    continue;
                }

                //group Bindings by target instanceq
                List <Binding> bindings = null;
                if (!resolved.TryGetValue(b.Target.Instance, out bindings))
                {
                    bindings = new List <Binding> ();
                    resolved [b.Target.Instance] = bindings;
                }
                bindings.Add(b);
                b.Resolved = true;
            }

            MethodInfo stringEquals = typeof(string).GetMethod
                                          ("Equals", new Type [3] {
                typeof(string), typeof(string), typeof(StringComparison)
            });
            Type             target_Type     = Bindings [0].Source.Instance.GetType();
            EventInfo        ei              = typeof(IValueChange).GetEvent("ValueChanged");
            MethodInfo       evtInvoke       = ei.EventHandlerType.GetMethod("Invoke");
            ParameterInfo [] evtParams       = evtInvoke.GetParameters();
            Type             handlerArgsType = evtParams [1].ParameterType;
            Type []          args            = { typeof(object), typeof(object), handlerArgsType };
            FieldInfo        fiNewValue      = typeof(ValueChangeEventArgs).GetField("NewValue");
            FieldInfo        fiMbName        = typeof(ValueChangeEventArgs).GetField("MemberName");

            //group;only one dynMethods by target (valuechanged event source)
            //changed value name tested in switch
            //IEnumerable<Binding[]> groupedByTarget = resolved.GroupBy (g => g.Target.Instance, g => g, (k, g) => g.ToArray ());
            foreach (List <Binding> grouped in resolved.Values)
            {
                int  i           = 0;
                Type source_Type = grouped [0].Target.Instance.GetType();

                DynamicMethod dm = null;
                ILGenerator   il = null;

                System.Reflection.Emit.Label [] jumpTable = null;
                System.Reflection.Emit.Label    endMethod = new System.Reflection.Emit.Label();

                #region Retrieve EventHandler parameter type
                //EventInfo ei = targetType.GetEvent ("ValueChanged");
                //no dynamic update if ValueChanged interface is not implemented
                if (source_Type.GetInterfaces().Contains(typeof(IValueChange)))
                {
                    dm = new DynamicMethod(grouped [0].CreateNewDynMethodId(),
                                           MethodAttributes.Family | MethodAttributes.FamANDAssem | MethodAttributes.NewSlot,
                                           CallingConventions.Standard,
                                           typeof(void),
                                           args,
                                           target_Type, true);

                    il = dm.GetILGenerator(256);

                    endMethod = il.DefineLabel();
                    jumpTable = new System.Reflection.Emit.Label [grouped.Count];
                    for (i = 0; i < grouped.Count; i++)
                    {
                        jumpTable [i] = il.DefineLabel();
                    }
                    il.DeclareLocal(typeof(string));
                    il.DeclareLocal(typeof(object));

                    il.Emit(OpCodes.Nop);
                    il.Emit(OpCodes.Ldarg_0);
                    //il.Emit(OpCodes.Isinst, sourceType);
                    //push new value onto stack
                    il.Emit(OpCodes.Ldarg_2);
                    il.Emit(OpCodes.Ldfld, fiNewValue);
                    il.Emit(OpCodes.Stloc_1);
                    //push name
                    il.Emit(OpCodes.Ldarg_2);
                    il.Emit(OpCodes.Ldfld, fiMbName);
                    il.Emit(OpCodes.Stloc_0);
                    il.Emit(OpCodes.Ldloc_0);
                    il.Emit(OpCodes.Brfalse, endMethod);
                }
                #endregion

                i = 0;
                foreach (Binding b in grouped)
                {
                    #region initialize target with actual value
                    object targetValue = null;
                    if (b.Target.Member != null)
                    {
                        if (b.Target.Member.MemberType == MemberTypes.Property)
                        {
                            targetValue = b.Target.Property.GetGetMethod().Invoke(b.Target.Instance, null);
                        }
                        else if (b.Target.Member.MemberType == MemberTypes.Field)
                        {
                            targetValue = b.Target.Field.GetValue(b.Target.Instance);
                        }
                        else if (b.Target.Member.MemberType == MemberTypes.Method)
                        {
                            MethodInfo mthSrc = b.Target.Method;
                            if (mthSrc.IsDefined(typeof(ExtensionAttribute), false))
                            {
                                targetValue = mthSrc.Invoke(null, new object [] { b.Target.Instance });
                            }
                            else
                            {
                                targetValue = mthSrc.Invoke(b.Target.Instance, null);
                            }
                        }
                        else
                        {
                            throw new Exception("unandled source member type for binding");
                        }
                    }
                    else if (string.IsNullOrEmpty(b.Expression))
                    {
                        targetValue = grouped [0].Target.Instance;                        //empty binding exp=> bound to target object by default
                    }
                    //TODO: handle other dest type conversions
                    if (b.Source.Property.PropertyType == typeof(string))
                    {
                        if (targetValue == null)
                        {
                            //set default value
                        }
                        else
                        {
                            targetValue = targetValue.ToString();
                        }
                    }
                    try {
                        if (targetValue != null)
                        {
                            b.Source.Property.GetSetMethod().Invoke
                                (b.Source.Instance, new object [] { b.Source.Property.PropertyType.Cast(targetValue) });
                        }
                        else
                        {
                            b.Source.Property.GetSetMethod().Invoke
                                (b.Source.Instance, new object [] { targetValue });
                        }
                    } catch (Exception ex) {
                        Debug.WriteLine(ex.ToString());
                    }
                    #endregion

                    //if no dyn update, skip jump table
                    if (il == null)
                    {
                        continue;
                    }

                    il.Emit(OpCodes.Ldloc_0);
                    if (b.Target.Member != null)
                    {
                        il.Emit(OpCodes.Ldstr, b.Target.Member.Name);
                    }
                    else
                    {
                        il.Emit(OpCodes.Ldstr, b.Expression.Split('/').LastOrDefault());
                    }
                    il.Emit(OpCodes.Ldc_I4_4);                     //StringComparison.Ordinal
                    il.Emit(OpCodes.Callvirt, stringEquals);
                    il.Emit(OpCodes.Brtrue, jumpTable [i]);
                    i++;
                }

                if (il == null)
                {
                    continue;
                }

                il.Emit(OpCodes.Br, endMethod);

                i = 0;
                foreach (Binding b in grouped)
                {
                    il.MarkLabel(jumpTable [i]);


                    //load 2 times to check first for null
                    il.Emit(OpCodes.Ldloc_1);
                    il.Emit(OpCodes.Ldloc_1);

                    System.Reflection.Emit.Label labSetValue = il.DefineLabel();
                    il.Emit(OpCodes.Brtrue, labSetValue);
                    //if null
                    il.Emit(OpCodes.Unbox_Any, b.Source.Property.PropertyType);
                    il.Emit(OpCodes.Callvirt, b.Source.Property.GetSetMethod());
                    il.Emit(OpCodes.Br, endMethod);

                    il.MarkLabel(labSetValue);
                    //new value not null

                    //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
                    Type sourceValueType = b.Source.Property.PropertyType;
                    if (b.Target.Member != null)
                    {
                        if (b.Target.Member.MemberType == MemberTypes.Property)
                        {
                            sourceValueType = b.Target.Property.PropertyType;
                        }
                        else if (b.Target.Member.MemberType == MemberTypes.Field)
                        {
                            sourceValueType = b.Target.Field.FieldType;
                        }
                        else
                        {
                            throw new Exception("unhandle target member type in binding");
                        }
                    }



                    if (b.Source.Property.PropertyType == typeof(string))
                    {
                        MemberReference tostring = new MemberReference(b.Source.Instance);
                        if (!tostring.TryFindMember("ToString"))
                        {
                            throw new Exception("ToString method not found");
                        }
                        il.Emit(OpCodes.Callvirt, tostring.Method);
                    }
                    else if (!sourceValueType.IsValueType)
                    {
                        il.Emit(OpCodes.Castclass, sourceValueType);
                    }
                    else if (b.Source.Property.PropertyType != sourceValueType)
                    {
                        il.Emit(OpCodes.Callvirt, CompilerServices.GetConvertMethod(b.Source.Property.PropertyType));
                    }
                    else
                    {
                        il.Emit(OpCodes.Unbox_Any, b.Source.Property.PropertyType);
                    }

                    il.Emit(OpCodes.Callvirt, b.Source.Property.GetSetMethod());

                    //il.BeginCatchBlock (typeof (Exception));
                    //il.Emit (OpCodes.Pop);
                    //il.EndExceptionBlock ();

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

                Delegate   del        = dm.CreateDelegate(ei.EventHandlerType, Bindings [0].Source.Instance);
                MethodInfo addHandler = ei.GetAddMethod();
                addHandler.Invoke(grouped [0].Target.Instance, new object [] { del });
            }
        }
Пример #3
0
        /// <summary>
        /// Emit MSIL for conversion from orig type to dest type
        /// </summary>
        internal static void emitConvert(ILGenerator il, Type origType, Type destType)
        {
            if (destType == CompilerServices.TObject)
            {
                return;
            }
            if (destType == typeof(string))
            {
                System.Reflection.Emit.Label emitNullStr = il.DefineLabel();
                System.Reflection.Emit.Label endConvert  = il.DefineLabel();
                il.Emit(OpCodes.Dup);
                il.Emit(OpCodes.Brfalse, emitNullStr);
                il.Emit(OpCodes.Callvirt, CompilerServices.miObjToString);
                il.Emit(OpCodes.Br, endConvert);
                il.MarkLabel(emitNullStr);
                il.Emit(OpCodes.Pop);                 //remove null string from stack
                il.Emit(OpCodes.Ldstr, "");           //replace with empty string
                il.MarkLabel(endConvert);
            }
            else if (origType.IsValueType)
            {
                if (destType != origType)
                {
                    MethodInfo miIO = getImplicitOp(origType, destType);
                    if (miIO != null)
                    {
                        System.Reflection.Emit.Label emitCreateDefault = il.DefineLabel();
                        System.Reflection.Emit.Label emitContinue      = il.DefineLabel();
                        LocalBuilder lbStruct = il.DeclareLocal(origType);
                        il.Emit(OpCodes.Dup);
                        il.Emit(OpCodes.Brfalse, emitCreateDefault);
                        il.Emit(OpCodes.Unbox_Any, origType);
                        il.Emit(OpCodes.Br, emitContinue);
                        il.MarkLabel(emitCreateDefault);
                        il.Emit(OpCodes.Pop);                         //pop null value
                        il.Emit(OpCodes.Ldloca, lbStruct);
                        il.Emit(OpCodes.Initobj, origType);
                        il.Emit(OpCodes.Ldloc, lbStruct);
                        il.MarkLabel(emitContinue);
                        il.Emit(OpCodes.Call, miIO);
                    }
                    else
                    {
                        il.Emit(OpCodes.Callvirt, CompilerServices.GetConvertMethod(destType));
                    }
                }
                else
                {
                    il.Emit(OpCodes.Unbox_Any, destType);                     //TODO:double check this
                }
            }
            else
            {
                if (destType.IsAssignableFrom(origType))
                {
                    il.Emit(OpCodes.Castclass, destType);
                }
                else
                {
                    //implicit conversion can't be defined from or to object base class,
                    //so we will check if object underlying type is one of the implicit converter of destType
                    if (origType == TObject)                      //test all implicit converter to destType on obj
                    {
                        System.Reflection.Emit.Label emitTestNextImpOp;
                        System.Reflection.Emit.Label emitImpOpFound = il.DefineLabel();
                        foreach (MethodInfo mi in destType.GetMethods(BindingFlags.Public | BindingFlags.Static))
                        {
                            if (mi.Name == "op_Implicit")
                            {
                                if (mi.GetParameters() [0].ParameterType == destType)
                                {
                                    continue;
                                }
                                emitTestNextImpOp = il.DefineLabel();
                                il.Emit(OpCodes.Dup);
                                il.Emit(OpCodes.Isinst, mi.GetParameters() [0].ParameterType);
                                il.Emit(OpCodes.Brfalse, emitTestNextImpOp);
                                if (mi.GetParameters() [0].ParameterType.IsValueType)
                                {
                                    il.Emit(OpCodes.Unbox_Any, mi.GetParameters() [0].ParameterType);
                                }
                                else
                                {
                                    il.Emit(OpCodes.Isinst, mi.GetParameters() [0].ParameterType);
                                }

                                il.Emit(OpCodes.Call, mi);
                                il.Emit(OpCodes.Br, emitImpOpFound);

                                il.MarkLabel(emitTestNextImpOp);
                            }
                        }
                        //il.Emit (OpCodes.Br, emitImpOpNotFound);
                        il.MarkLabel(emitImpOpFound);
                    }
                    else                        //search both orig and dest types for implicit operators
                    {
                        MethodInfo miIO = getImplicitOp(origType, destType);
                        if (miIO != null)
                        {
                            il.Emit(OpCodes.Call, miIO);
                        }
                    }
                }
            }
        }