From 366e3e09cd941a4bb80afcba87157764b007770c Mon Sep 17 00:00:00 2001 From: jpbruyere Date: Thu, 22 Dec 2016 12:29:10 +0100 Subject: [PATCH] =?utf8?q?Add=20in=20tree=20handler=20at=20end=20of=20pars?= =?utf8?q?ing=20just=20after=20name=20resolution=20Move=20several=20static?= =?utf8?q?=20func=20for=20emit=20in=20CompilerService=20class=20=09modifi?= =?utf8?q?=C3=A9=C2=A0:=20=20=20=20=20=20=20=20=20src/CompilerServices/Com?= =?utf8?q?pilerServices.cs=20=09modifi=C3=A9=C2=A0:=20=20=20=20=20=20=20?= =?utf8?q?=20=20src/IML/BindingDefinition.cs=20=09modifi=C3=A9=C2=A0:=20?= =?utf8?q?=20=20=20=20=20=20=20=20src/IML/Context.cs=20=09modifi=C3=A9?= =?utf8?q?=C2=A0:=20=20=20=20=20=20=20=20=20src/Instantiator.cs?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- src/CompilerServices/CompilerServices.cs | 130 +++++++++++++++ src/IML/BindingDefinition.cs | 2 + src/IML/Context.cs | 89 +++++++--- src/Instantiator.cs | 199 ++++------------------- 4 files changed, 229 insertions(+), 191 deletions(-) diff --git a/src/CompilerServices/CompilerServices.cs b/src/CompilerServices/CompilerServices.cs index 16ad5d8e..de49d32d 100644 --- a/src/CompilerServices/CompilerServices.cs +++ b/src/CompilerServices/CompilerServices.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Xml; +using Crow.IML; namespace Crow @@ -665,6 +666,135 @@ namespace Crow return Activator.CreateInstance (dstType); return null; } + public static void emitGetInstance (ILGenerator il, NodeAddress orig, NodeAddress dest){ + if (orig.Count < dest.Count) { + for (int i = orig.Count - 1; i < dest.Count - 1; i++) + emitGetChild (il, dest [i].CrowType, dest [i + 1].Index); + } else { + for (int j = dest.Count; j < orig.Count; j++) + il.Emit (OpCodes.Callvirt, typeof(ILayoutable).GetProperty ("Parent").GetGetMethod ()); + } + } + public static void emitGetInstance (ILGenerator il, NodeAddress dest){ + for (int i = 0; i < dest.Count - 1; i++) + emitGetChild (il, dest [i].CrowType, dest [i + 1].Index); + } + public static void emitGetChild(ILGenerator il, Type parentType, int index){ + if (typeof (Group).IsAssignableFrom (parentType)) { + il.Emit (OpCodes.Ldfld, typeof(Group).GetField ("children", BindingFlags.Instance | BindingFlags.NonPublic)); + il.Emit(OpCodes.Ldc_I4, index); + il.Emit (OpCodes.Callvirt, typeof(List).GetMethod("get_Item", new Type[] { typeof(Int32) })); + return; + } + if (typeof(Container).IsAssignableFrom (parentType) || index < 0) { + il.Emit (OpCodes.Ldfld, typeof(PrivateContainer).GetField ("child", BindingFlags.Instance | BindingFlags.NonPublic)); + return; + } + if (typeof(TemplatedContainer).IsAssignableFrom (parentType)) { + il.Emit (OpCodes.Callvirt, typeof(TemplatedContainer).GetProperty ("Content").GetGetMethod ()); + return; + } + if (typeof(TemplatedGroup).IsAssignableFrom (parentType)) { + il.Emit (OpCodes.Callvirt, typeof(TemplatedGroup).GetProperty ("Items").GetGetMethod ()); + il.Emit(OpCodes.Ldc_I4, index); + il.Emit (OpCodes.Callvirt, typeof(List).GetMethod("get_Item", new Type[] { typeof(Int32) })); + return; + } + } + /// + /// Emit conversion from orig type to dest type + /// + public static void emitConvert(ILGenerator il, Type origType, Type destType){ + if (destType == typeof(string)) + il.Emit (OpCodes.Callvirt, CompilerServices.miObjToString); + else if (origType.IsValueType) { + if (destType != origType) { + il.Emit (OpCodes.Callvirt, CompilerServices.GetConvertMethod (destType)); + }else + il.Emit (OpCodes.Unbox_Any, destType);//TODO:double check this + } else { + if (origType.IsAssignableFrom(destType)) + il.Emit (OpCodes.Castclass, destType); + else { + MethodInfo miIO = getImplicitOp (origType, destType); + if (miIO != null) + il.Emit (OpCodes.Callvirt, miIO); + } + } + } + /// + /// check type of current object on the stack and convert to dest type, + /// use loc_0 so store it as object!!! + /// + public 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)) { + il.Emit (OpCodes.Callvirt, CompilerServices.miObjToString); + } 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 + il.Emit (OpCodes.Ldloc_0); + il.Emit (OpCodes.Callvirt, typeof(object).GetMethod ("GetType")); + il.Emit (OpCodes.Ldtoken, dstType);//push destination property type for testing + il.Emit (OpCodes.Call, CompilerServices.miGetTypeFromHandle); + il.Emit (OpCodes.Call, typeof(CompilerServices).GetMethod ("getImplicitOp", BindingFlags.Static | BindingFlags.Public)); + 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, typeof(object)); + 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, typeof(object));//set the array element at index 0 + il.Emit (OpCodes.Callvirt, typeof(MethodInfo).GetMethod("Invoke", new Type[] { typeof(object), typeof (object[])})); + } + + il.MarkLabel (endConvert); + } + /// + /// search for an implicit conversion method in origine or destination classes + /// + public static MethodInfo getImplicitOp(Type origType, Type dstType){ + foreach(MethodInfo mi in origType.GetMethods(BindingFlags.Public|BindingFlags.Static)){ + if (mi.Name == "op_Implicit") { + if (mi.ReturnType == dstType && mi.GetParameters ().FirstOrDefault ().ParameterType == origType) + return mi; + } + } + foreach(MethodInfo mi in dstType.GetMethods(BindingFlags.Public|BindingFlags.Static)){ + if (mi.Name == "op_Implicit") { + if (mi.ReturnType == dstType && mi.GetParameters ().FirstOrDefault ().ParameterType == origType) + return mi; + } + } + return null; + } } } diff --git a/src/IML/BindingDefinition.cs b/src/IML/BindingDefinition.cs index 2c3fecdc..59b45167 100644 --- a/src/IML/BindingDefinition.cs +++ b/src/IML/BindingDefinition.cs @@ -53,6 +53,8 @@ namespace Crow.IML public bool IsDataSourceBinding { get { return TargetNA == null; }} public bool IsTemplateBinding { get { return IsDataSourceBinding ? false : TargetNA.Count == 0; }} public bool HasUnresolvedTargetName { get { return !string.IsNullOrEmpty(TargetName); }} + public MemberAddress SourceMemberAddress { get { return new MemberAddress (SourceNA, SourceMember);}} + public MemberAddress TargetMemberAddress { get { return new MemberAddress (TargetNA, TargetMember);}} /// /// replace the target node address with corresponding named node address, and clear the target name once resolved diff --git a/src/IML/Context.cs b/src/IML/Context.cs index 393bab21..ec97c3d8 100644 --- a/src/IML/Context.cs +++ b/src/IML/Context.cs @@ -32,7 +32,7 @@ namespace Crow.IML public string DataSourceMember; } /// - /// Context while parsing IML + /// Context while parsing IML, this will store what's needed only while parsing and not during instancing /// public class Context { @@ -44,12 +44,15 @@ namespace Crow.IML //public SubNodeType curSubNodeType; public NodeStack nodesStack = new NodeStack (); + /// store addresses of named node for name resolution at end of parsing public Dictionary> Names = new Dictionary>(); - + /// Store non datasource binding (in tree and template) by origine and orig member public Dictionary>> Bindings = new Dictionary>>(); + /// Store binding with name in target, will be resolved at end of parsing public List UnresolvedTargets = new List(); + public Context (Type rootType) { RootType = rootType; @@ -97,33 +100,50 @@ namespace Crow.IML Names[name] = new List(); Names[name].Add(CurrentNodeAddress); } - public void ResolveNames (){ + public void ProcessBindingDefinition(){//TODO:methodinfo fetching is redundant with early parsing foreach (BindingDefinition bd in UnresolvedTargets) { - if (!Names.ContainsKey (bd.TargetName)) { - System.Diagnostics.Debug.WriteLine ("Target Name '" + bd.TargetName + "' not found"); - continue; - } - NodeAddress resolvedNA = null; - foreach (NodeAddress na in Names[bd.TargetName]) { - bool naMatch = true; - for (int i = 0; i < bd.TargetNA.Count; i++) { - if (bd.TargetNA [i] != na [i]) { - naMatch = false; - break; - } + if (bd.HasUnresolvedTargetName) { + try { + ResolveName (bd); + } catch (Exception ex) { + System.Diagnostics.Debug.WriteLine (ex.ToString ()); + continue; } - if (naMatch) { - resolvedNA = na; + } + + MemberInfo miSource = bd.SourceMemberAddress.member; + if (miSource == null) + throw new Exception ("Source member '" + bd.SourceMember + "' not found"); + if (miSource.MemberType == MemberTypes.Event) + emitHandlerMethodAddition (bd, miSource as EventInfo); + else + StorePropertyBinding (bd); + } + } + public void ResolveName (BindingDefinition bd){ + + if (!Names.ContainsKey (bd.TargetName)) + throw new Exception ("Target Name '" + bd.TargetName + "' not found"); + + NodeAddress resolvedNA = null; + foreach (NodeAddress na in Names[bd.TargetName]) { + bool naMatch = true; + for (int i = 0; i < bd.TargetNA.Count; i++) { + if (bd.TargetNA [i] != na [i]) { + naMatch = false; break; } } - if (resolvedNA == null) - System.Diagnostics.Debug.WriteLine ("Target Name '" + bd.TargetName + "' not found"); - else { - bd.ResolveTargetName (resolvedNA); - StorePropertyBinding (bd); + if (naMatch) { + resolvedNA = na; + break; } } + + if (resolvedNA == null) + throw new Exception ("Target Name '" + bd.TargetName + "' not found"); + + bd.ResolveTargetName (resolvedNA); } void initILGen () @@ -144,5 +164,30 @@ namespace Crow.IML il.Emit(OpCodes.Callvirt, typeof(List).GetMethod("get_Item", new Type[] { typeof(Int32) })); il.Emit(OpCodes.Callvirt, evt.AddMethod);//call add event } + /// + /// Emits the handler method addition, done at end of parsing, Loc_0 is root node instance + /// + /// Bd. + /// passed as arg to prevent refetching it for the 3rd time + public void emitHandlerMethodAddition(BindingDefinition bd, EventInfo evt){ + //fetch source instance with address for handler addition (as 1st arg of handler.add) + il.Emit (OpCodes.Ldloc_0);//push root + CompilerServices.emitGetInstance (il, bd.SourceNA); + + //load handlerType of sourceEvent to create handler delegate (1st arg) + il.Emit (OpCodes.Ldtoken, evt.EventHandlerType); + il.Emit (OpCodes.Call, CompilerServices.miGetTypeFromHandle); + //load target the where the method is defined (2nd arg) + il.Emit (OpCodes.Ldloc_0); + CompilerServices.emitGetInstance (il, bd.TargetNA); + //load methodInfo (3rd arg) + il.Emit (OpCodes.Ldtoken, bd.TargetMemberAddress.member as MethodInfo); + il.Emit (OpCodes.Call, CompilerServices.miGetTypeFromHandle); + + il.Emit (OpCodes.Callvirt, typeof(Delegate).GetMethod ("CreateDelegate", + new Type[] { typeof(Type), typeof(object), typeof(MethodInfo) }));//create bound delegate + + il.Emit (OpCodes.Callvirt, evt.AddMethod);//call add event + } } } \ No newline at end of file diff --git a/src/Instantiator.cs b/src/Instantiator.cs index d4178dbf..47fcb177 100644 --- a/src/Instantiator.cs +++ b/src/Instantiator.cs @@ -112,7 +112,7 @@ namespace Crow foreach (int idx in templateCachedDelegateIndices) ctx.emitCachedDelegateHandlerAddition(idx, typeof(GraphicObject).GetEvent("ParentChanged")); - ctx.ResolveNames (); + ctx.ProcessBindingDefinition (); emitBindingDelegates (ctx); @@ -546,7 +546,7 @@ namespace Crow if (lopParts.Length > 1) { NodeAddress lopNA = getNodeAdressFromBindingExp (currentNode, lopParts); - emitGetInstance (il, currentNode, lopNA); + CompilerServices.emitGetInstance (il, currentNode, lopNA); lopType = lopNA.NodeType; } @@ -629,21 +629,11 @@ namespace Crow NodeAddress currentNode = ctx.CurrentNodeAddress; BindingDefinition bindingDef = splitBindingExp (currentNode, sourceEvent.Name, expression); - if (bindingDef.HasUnresolvedTargetName) - return; - - string bindOnEventName = null; - - if (bindingDef.TargetNA == null)//datasource handler - bindOnEventName = "DataSourceChanged"; - else if (bindingDef.TargetNA.Count == 0)//out of tree template handler - bindOnEventName = "ParentChanged"; - - if (!string.IsNullOrEmpty(bindOnEventName)){ + if (bindingDef.IsTemplateBinding | bindingDef.IsDataSourceBinding) { //we need to bind datasource method to source event DynamicMethod dm = new DynamicMethod ("dyn_dschangedForHandler", - typeof (void), - CompilerServices.argsBoundDSChange, true); + typeof(void), + CompilerServices.argsBoundDSChange, true); ILGenerator il = dm.GetILGenerator (256); System.Reflection.Emit.Label cancel = il.DefineLabel (); @@ -659,7 +649,7 @@ namespace Crow 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, typeof(CompilerServices).GetMethod("getMethodInfoWithReflexion", BindingFlags.Static | BindingFlags.Public)); + il.Emit (OpCodes.Call, typeof(CompilerServices).GetMethod ("getMethodInfoWithReflexion", BindingFlags.Static | BindingFlags.Public)); il.Emit (OpCodes.Stloc_0);//save MethodInfo il.Emit (OpCodes.Ldloc_0);//push mi for test if null @@ -667,18 +657,18 @@ namespace Crow il.Emit (OpCodes.Ldarg_1);//load datasource change source where the event handler is as 1st arg of handler.add if (bindingDef.IsTemplateBinding)//fetch source instance with address - emitGetInstance (il, bindingDef.SourceNA); + CompilerServices.emitGetInstance (il, bindingDef.SourceNA); - //loat handlerType of sourceEvent to create delegate (1st arg) - il.Emit(OpCodes.Ldtoken, sourceEvent.EventHandlerType); + //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, typeof(Delegate).GetMethod ("CreateDelegate", - new Type[] {typeof(Type), typeof(object), typeof(MethodInfo)}));//create bound delegate - il.Emit(OpCodes.Callvirt, sourceEvent.AddMethod);//call add event + new Type[] { typeof(Type), typeof(object), typeof(MethodInfo) }));//create bound delegate + il.Emit (OpCodes.Callvirt, sourceEvent.AddMethod);//call add event System.Reflection.Emit.Label finish = il.DefineLabel (); il.Emit (OpCodes.Br, finish); @@ -689,12 +679,14 @@ namespace Crow //store dschange delegate in instatiator instance for access while instancing graphic object int delDSIndex = cachedDelegates.Count; - cachedDelegates.Add(dm.CreateDelegate (CompilerServices.ehTypeDSChange, this)); + cachedDelegates.Add (dm.CreateDelegate (CompilerServices.ehTypeDSChange, this)); - if (bindingDef.TargetNA == null) - ctx.emitCachedDelegateHandlerAddition(delDSIndex, typeof(GraphicObject).GetEvent("DataSourceChanged")); + if (bindingDef.IsDataSourceBinding) + ctx.emitCachedDelegateHandlerAddition (delDSIndex, typeof(GraphicObject).GetEvent ("DataSourceChanged")); else //template handler binding - templateCachedDelegateIndices.Add(delDSIndex); + templateCachedDelegateIndices.Add (delDSIndex); + } else {//normal in tree handler binding, store until tree is complete (end of parse) + } } /// @@ -776,10 +768,10 @@ namespace Crow il.Emit (OpCodes.Ldarg_0);//load source instance of ValueChanged event ilPC.Emit (OpCodes.Ldarg_2);//load destination instance to set actual value of member ilPC.Emit (OpCodes.Ldfld, CompilerServices.fiDSCNewDS); - emitGetChild (il, typeof(TemplatedControl), -1); - emitGetInstance (il, ma.Address); - emitGetChild (ilPC, typeof(TemplatedControl), -1); - emitGetInstance (ilPC, ma.Address); + CompilerServices.emitGetChild (il, typeof(TemplatedControl), -1); + CompilerServices.emitGetInstance (il, ma.Address); + CompilerServices.emitGetChild (ilPC, typeof(TemplatedControl), -1); + CompilerServices.emitGetInstance (ilPC, ma.Address); //load new value il.Emit (OpCodes.Ldarg_1); @@ -790,9 +782,9 @@ namespace Crow ilPC.Emit (OpCodes.Ldloc_1);//push mi for value fetching ilPC.Emit (OpCodes.Call, typeof(CompilerServices).GetMethod("getValueWithReflexion", BindingFlags.Static | BindingFlags.Public)); - emitConvert (il, ma.Property.PropertyType); + CompilerServices.emitConvert (il, ma.Property.PropertyType); - emitConvert (ilPC, ma.Property.PropertyType); + CompilerServices.emitConvert (ilPC, ma.Property.PropertyType); il.Emit (OpCodes.Callvirt, ma.Property.GetSetMethod()); ilPC.Emit (OpCodes.Callvirt, ma.Property.GetSetMethod()); @@ -884,12 +876,12 @@ namespace Crow NodeAddress destination = ma.Address; - emitGetInstance (il, origine, destination); + CompilerServices.emitGetInstance (il, origine, destination); if (origineType != null){//prop less binding, no init requiered //for initialisation dynmeth, load current instance ilInit.Emit(OpCodes.Ldarg_0); - emitGetInstance (ilInit, origine, destination); + CompilerServices.emitGetInstance (ilInit, origine, destination); //init dynmeth: load actual value ilInit.Emit (OpCodes.Ldarg_0); @@ -900,12 +892,12 @@ namespace Crow il.Emit (OpCodes.Ldfld, typeof (ValueChangeEventArgs).GetField ("NewValue")); if (origineType == null)//property less binding, no init - emitConvert (il, ma.Property.PropertyType); + CompilerServices.emitConvert (il, ma.Property.PropertyType); else { if (origineType.IsValueType) ilInit.Emit(OpCodes.Box, origineType); - emitConvert (ilInit, origineType, ma.Property.PropertyType); - emitConvert (il, origineType, ma.Property.PropertyType); + CompilerServices.emitConvert (ilInit, origineType, ma.Property.PropertyType); + CompilerServices.emitConvert (il, origineType, ma.Property.PropertyType); ilInit.Emit (OpCodes.Callvirt, ma.Property.GetSetMethod());//set init value } @@ -970,7 +962,7 @@ namespace Crow //memberless binding, if targetMember exists, it will be used to determine target //value type for conversion - emitConvert (il, piOrigine.PropertyType); + CompilerServices.emitConvert (il, piOrigine.PropertyType); il.Emit (OpCodes.Callvirt, piOrigine.GetSetMethod ()); @@ -1028,7 +1020,7 @@ namespace Crow il.Emit (OpCodes.Ldloc_1);//push mi for value fetching il.Emit (OpCodes.Call, typeof(CompilerServices).GetMethod("getValueWithReflexion", BindingFlags.Static | BindingFlags.Public)); } - emitConvert (il, piOrigine.PropertyType); + CompilerServices.emitConvert (il, piOrigine.PropertyType); il.Emit (OpCodes.Callvirt, piOrigine.GetSetMethod ()); if (!string.IsNullOrEmpty(dataSourceMember)){ @@ -1052,137 +1044,6 @@ namespace Crow ctx.emitCachedDelegateHandlerAddition(delDSIndex, typeof(GraphicObject).GetEvent("DataSourceChanged")); } - - void emitGetInstance (ILGenerator il, NodeAddress orig, NodeAddress dest){ - if (orig.Count < dest.Count) { - for (int i = orig.Count - 1; i < dest.Count - 1; i++) - emitGetChild (il, dest [i].CrowType, dest [i + 1].Index); - } else { - for (int j = dest.Count; j < orig.Count; j++) - il.Emit (OpCodes.Callvirt, typeof(ILayoutable).GetProperty ("Parent").GetGetMethod ()); - } - } - void emitGetInstance (ILGenerator il, NodeAddress dest){ - for (int i = 0; i < dest.Count - 1; i++) - emitGetChild (il, dest [i].CrowType, dest [i + 1].Index); - } - void emitGetChild(ILGenerator il, Type parentType, int index){ - if (typeof (Group).IsAssignableFrom (parentType)) { - il.Emit (OpCodes.Ldfld, typeof(Group).GetField ("children", BindingFlags.Instance | BindingFlags.NonPublic)); - il.Emit(OpCodes.Ldc_I4, index); - il.Emit (OpCodes.Callvirt, typeof(List).GetMethod("get_Item", new Type[] { typeof(Int32) })); - return; - } - if (typeof(Container).IsAssignableFrom (parentType) || index < 0) { - il.Emit (OpCodes.Ldfld, typeof(PrivateContainer).GetField ("child", BindingFlags.Instance | BindingFlags.NonPublic)); - return; - } - if (typeof(TemplatedContainer).IsAssignableFrom (parentType)) { - il.Emit (OpCodes.Callvirt, typeof(TemplatedContainer).GetProperty ("Content").GetGetMethod ()); - return; - } - if (typeof(TemplatedGroup).IsAssignableFrom (parentType)) { - il.Emit (OpCodes.Callvirt, typeof(TemplatedGroup).GetProperty ("Items").GetGetMethod ()); - il.Emit(OpCodes.Ldc_I4, index); - il.Emit (OpCodes.Callvirt, typeof(List).GetMethod("get_Item", new Type[] { typeof(Int32) })); - return; - } - } - /// - /// Emit conversion from orig type to dest type - /// - void emitConvert(ILGenerator il, Type origType, Type destType){ - if (destType == typeof(string)) - il.Emit (OpCodes.Callvirt, CompilerServices.miObjToString); - else if (origType.IsValueType) { - if (destType != origType) { - il.Emit (OpCodes.Callvirt, CompilerServices.GetConvertMethod (destType)); - }else - il.Emit (OpCodes.Unbox_Any, destType);//TODO:double check this - } else { - if (origType.IsAssignableFrom(destType)) - il.Emit (OpCodes.Castclass, destType); - else { - MethodInfo miIO = getImplicitOp (origType, destType); - if (miIO != null) - il.Emit (OpCodes.Callvirt, miIO); - } - } - } - /// - /// check type of current object on the stack and convert to dest type, - /// use loc_0 so store it as object!!! - /// - 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)) { - il.Emit (OpCodes.Callvirt, CompilerServices.miObjToString); - } 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 - il.Emit (OpCodes.Ldloc_0); - il.Emit (OpCodes.Callvirt, typeof(object).GetMethod ("GetType")); - il.Emit (OpCodes.Ldtoken, dstType);//push destination property type for testing - il.Emit (OpCodes.Call, CompilerServices.miGetTypeFromHandle); - il.Emit (OpCodes.Call, typeof(Instantiator).GetMethod ("getImplicitOp", BindingFlags.Static | BindingFlags.Public)); - 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, typeof(object)); - 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, typeof(object));//set the array element at index 0 - il.Emit (OpCodes.Callvirt, typeof(MethodInfo).GetMethod("Invoke", new Type[] { typeof(object), typeof (object[])})); - } - - il.MarkLabel (endConvert); - } - - /// - /// search for an implicit conversion method in origine or destination classes - /// - public static MethodInfo getImplicitOp(Type origType, Type dstType){ - foreach(MethodInfo mi in origType.GetMethods(BindingFlags.Public|BindingFlags.Static)){ - if (mi.Name == "op_Implicit") { - if (mi.ReturnType == dstType && mi.GetParameters ().FirstOrDefault ().ParameterType == origType) - return mi; - } - } - foreach(MethodInfo mi in dstType.GetMethods(BindingFlags.Public|BindingFlags.Static)){ - if (mi.Name == "op_Implicit") { - if (mi.ReturnType == dstType && mi.GetParameters ().FirstOrDefault ().ParameterType == origType) - return mi; - } - } - return null; - } } } -- 2.47.3