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