//data is on the stack void emitGetSubData(ILGenerator il, Type dataType) { MethodInfo miGetDatas = dataType.GetMethod(fetchMethodName, new Type[] {}); if (miGetDatas == null) { miGetDatas = CompilerServices.SearchExtMethod(dataType, fetchMethodName); } if (miGetDatas == null) //in last resort, search among properties { PropertyInfo piDatas = dataType.GetProperty(fetchMethodName); if (piDatas == null) { FieldInfo fiDatas = dataType.GetField(fetchMethodName); if (fiDatas == null) //and among fields { throw new Exception("Fetch data member not found in ItemTemplate: " + fetchMethodName); } il.Emit(OpCodes.Ldfld, fiDatas); return; } miGetDatas = piDatas.GetGetMethod(); if (miGetDatas == null) { throw new Exception("Read only property for fetching data in ItemTemplate: " + fetchMethodName); } } il.Emit(OpCodes.Callvirt, miGetDatas); }
/// <summary> /// Inits il generator, RootType must have been read first /// </summary> void InitEmitter() { dm = new DynamicMethod("dyn_instantiator", MethodAttributes.Family | MethodAttributes.FamANDAssem | MethodAttributes.NewSlot, CallingConventions.Standard, typeof(void), new Type[] { typeof(object), typeof(Interface) }, RootType, true); il = dm.GetILGenerator(256); il.DeclareLocal(typeof(GraphicObject)); il.Emit(OpCodes.Nop); //set local GraphicObject to root object passed as 1st argument il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Stloc_0); CompilerServices.emitSetCurInterface(il); }
/// <summary> /// Try to find member by name in instance class or, if not found, /// in extension methods /// </summary> /// <returns>True if found, false otherwise</returns> /// <param name="_memberName">Member name to search for</param> public bool TryFindMember(string _memberName) { if (Instance == null) { return(false); } Type t = Instance.GetType(); Member = t.GetMember(_memberName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance).FirstOrDefault(); #region search for extensions methods if member not found in type if (Member == null && !string.IsNullOrEmpty(_memberName)) { Assembly a = Assembly.GetExecutingAssembly(); Member = CompilerServices.GetExtensionMethods(a, t).Where(em => em.Name == _memberName).FirstOrDefault(); } #endregion return(Member != null); }
protected void loadItem(object o, Group page, string _dataTest) { if (o == null) //TODO:surely a threading sync problem { return; } GraphicObject g = null; ItemTemplate iTemp = null; Type dataType = o.GetType(); string itempKey = dataType.FullName; if (_dataTest != "TypeOf") { itempKey = getItempKey(dataType, o, _dataTest); } if (ItemTemplates.ContainsKey(itempKey)) { iTemp = ItemTemplates [itempKey]; } else { foreach (string it in ItemTemplates.Keys) { Type t = CompilerServices.tryGetType(it); if (t == null) { continue; } if (t.IsAssignableFrom(dataType)) //TODO:types could be cached { iTemp = ItemTemplates [it]; break; } } if (iTemp == null) { iTemp = ItemTemplates ["default"]; } } lock (IFace.LayoutMutex) { g = iTemp.CreateInstance(); #if DESIGN_MODE g.design_isTGItem = true; #endif page.AddChild(g); // if (isPaged) g.LogicalParent = this; g.MouseDown += itemClick; } if (iTemp.Expand != null && g is Expandable) { Expandable e = g as Expandable; e.Expand += iTemp.Expand; e.GetIsExpandable = iTemp.HasSubItems; } g.DataSource = o; }
/// <summary> Loads the default values from XML attributes default </summary> public void loadDefaultValues() { #if DEBUG_LOAD Debug.WriteLine ("LoadDefValues for " + this.ToString ()); #endif Type thisType = this.GetType (); if (!string.IsNullOrEmpty (Style)) { if (Interface.DefaultValuesLoader.ContainsKey (Style)) { Interface.DefaultValuesLoader [Style] (this); return; } } else { if (Interface.DefaultValuesLoader.ContainsKey (thisType.FullName)) { Interface.DefaultValuesLoader [thisType.FullName] (this); return; } else if (!Interface.Styling.ContainsKey (thisType.FullName)) { if (Interface.DefaultValuesLoader.ContainsKey (thisType.Name)) { Interface.DefaultValuesLoader [thisType.Name] (this); return; } } } List<Style> styling = new List<Style>(); //Search for a style matching : //1: Full class name, with full namespace //2: class name //3: style may have been registered with their ressource ID minus .style extention // those files being placed in a Styles folder string styleKey = Style; if (!string.IsNullOrEmpty (Style)) { if (Interface.Styling.ContainsKey (Style)) { styling.Add (Interface.Styling [Style]); } } if (Interface.Styling.ContainsKey (thisType.FullName)) { styling.Add (Interface.Styling [thisType.FullName]); if (string.IsNullOrEmpty (styleKey)) styleKey = thisType.FullName; } if (Interface.Styling.ContainsKey (thisType.Name)) { styling.Add (Interface.Styling [thisType.Name]); if (string.IsNullOrEmpty (styleKey)) styleKey = thisType.Name; } if (string.IsNullOrEmpty (styleKey)) styleKey = thisType.FullName; //Reflexion being very slow compared to dyn method or delegates, //I compile the initial values coded in the CustomAttribs of the class, //all other instance of this type would not longer use reflexion to init properly //but will fetch the dynamic initialisation method compiled for this precise type //TODO:measure speed gain. #region Delfault values Loading dynamic compilation DynamicMethod dm = null; ILGenerator il = null; dm = new DynamicMethod("dyn_loadDefValues", MethodAttributes.Family | MethodAttributes.FamANDAssem | MethodAttributes.NewSlot, CallingConventions.Standard, typeof(void),new Type[] {CompilerServices.TObject},thisType,true); il = dm.GetILGenerator(256); il.DeclareLocal(CompilerServices.TObject); il.Emit(OpCodes.Nop); //set local GraphicObject to root object passed as 1st argument il.Emit (OpCodes.Ldarg_0); il.Emit (OpCodes.Stloc_0); foreach (EventInfo ei in thisType.GetEvents(BindingFlags.Public | BindingFlags.Instance)) { string expression; if (!getDefaultEvent(ei, styling, out expression)) continue; //TODO:dynEventHandler could be cached somewhere, maybe a style instanciator class holding the styling delegate and bound to it. foreach (string exp in CompilerServices.splitOnSemiColumnOutsideAccolades(expression)) { string trimed = exp.Trim(); if (trimed.StartsWith ("{", StringComparison.OrdinalIgnoreCase)){ il.Emit (OpCodes.Ldloc_0);//load this as 1st arg of event Add //push eventInfo as 1st arg of compile il.Emit (OpCodes.Ldloc_0); il.Emit (OpCodes.Call, CompilerServices.miGetType); il.Emit (OpCodes.Ldstr, ei.Name);//push event name il.Emit (OpCodes.Call, CompilerServices.miGetEvent); //push expression as 2nd arg of compile il.Emit (OpCodes.Ldstr, trimed.Substring (1, trimed.Length - 2)); //push null as 3rd arg, currentNode, not known when instanciing il.Emit (OpCodes.Ldnull); il.Emit (OpCodes.Callvirt, CompilerServices.miCompileDynEventHandler); il.Emit (OpCodes.Castclass, ei.EventHandlerType); il.Emit (OpCodes.Callvirt, ei.AddMethod); }else Debug.WriteLine("error in styling, event not handled : " + trimed); } } foreach (PropertyInfo pi in thisType.GetProperties(BindingFlags.Public | BindingFlags.Instance)) { if (pi.GetSetMethod () == null) continue; object defaultValue; if (!getDefaultValue (pi, styling, out defaultValue)) continue; CompilerServices.EmitSetValue (il, pi, defaultValue); } il.Emit(OpCodes.Ret); #endregion try { Interface.DefaultValuesLoader[styleKey] = (Interface.LoaderInvoker)dm.CreateDelegate(typeof(Interface.LoaderInvoker)); Interface.DefaultValuesLoader[styleKey] (this); } catch (Exception ex) { throw new Exception ("Error applying style <" + styleKey + ">:", ex); } }
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> /// Parse child node an generate corresponding msil /// </summary> void readChildren(IMLReader reader, Type crowType, bool templateLoading = false) { MethodInfo miAddChild = null; bool endTagReached = false; while (reader.Read()) { switch (reader.NodeType) { case XmlNodeType.EndElement: endTagReached = true; break; case XmlNodeType.Element: //Templates if (reader.Name == "Template" || reader.Name == "ItemTemplate") { reader.Skip(); continue; } if (miAddChild == null) { if (typeof(Group).IsAssignableFrom(crowType)) { miAddChild = typeof(Group).GetMethod("AddChild"); } else if (typeof(Container).IsAssignableFrom(crowType)) { miAddChild = typeof(Container).GetMethod("SetChild"); } else if (typeof(TemplatedContainer).IsAssignableFrom(crowType) && !templateLoading) { miAddChild = typeof(TemplatedContainer).GetProperty("Content").GetSetMethod(); } else if (typeof(TemplatedGroup).IsAssignableFrom(crowType) && !templateLoading) { miAddChild = typeof(TemplatedGroup).GetMethod("AddItem", BindingFlags.Instance | BindingFlags.Public); } else if (typeof(TemplatedControl).IsAssignableFrom(crowType)) { miAddChild = typeof(TemplatedControl).GetMethod("loadTemplate", BindingFlags.Instance | BindingFlags.NonPublic); } else if (typeof(PrivateContainer).IsAssignableFrom(crowType)) { miAddChild = typeof(PrivateContainer).GetMethod("SetChild", BindingFlags.Instance | BindingFlags.NonPublic); } } //push current instance on stack for parenting //loc_0 will be used for child reader.il.Emit(OpCodes.Ldloc_0); Type t = Type.GetType("Crow." + reader.Name); if (t == null) { Assembly a = Assembly.GetEntryAssembly(); foreach (Type expT in a.GetExportedTypes()) { if (expT.Name == reader.Name) { t = expT; } } } if (t == null) { throw new Exception(reader.Name + " type not found"); } reader.il.Emit(OpCodes.Newobj, t.GetConstructors() [0]); //TODO:search parameterless ctor reader.il.Emit(OpCodes.Stloc_0); //child is now loc_0 CompilerServices.emitSetCurInterface(il); reader.emitLoader(t); reader.il.Emit(OpCodes.Ldloc_0); //load child on stack for parenting if (miAddChild == null) { System.Diagnostics.Debugger.Break(); } reader.il.Emit(OpCodes.Callvirt, miAddChild); reader.il.Emit(OpCodes.Stloc_0); //reset local to current go reader.il.Emit(OpCodes.Ldloc_0); //save current go onto the stack if child has to be added break; } if (endTagReached) { break; } } }
void emitLoader(Type crowType) { string tmpXml = ReadOuterXml(); il.Emit(OpCodes.Ldloc_0); //save current go onto the stack if child has to be added #region Template and ItemTemplates loading if (typeof(TemplatedControl).IsAssignableFrom(crowType)) { //if its a template, first read template elements using (IMLReader reader = new IMLReader(il, tmpXml)) { string templatePath = reader.GetAttribute("Template"); //string itemTemplatePath = reader.GetAttribute ("ItemTemplate"); List <string[]> itemTemplateIds = new List <string[]> (); bool inlineTemplate = false; reader.Read(); int depth = reader.Depth + 1; while (reader.Read()) { if (!reader.IsStartElement() || reader.Depth > depth) { continue; } if (reader.Name == "Template") { inlineTemplate = true; reader.Read(); readChildren(reader, crowType, true); } else if (reader.Name == "ItemTemplate") { string dataType = "default", datas = "", path = ""; while (reader.MoveToNextAttribute()) { if (reader.Name == "DataType") { dataType = reader.Value; } else if (reader.Name == "Data") { datas = reader.Value; } else if (reader.Name == "Path") { path = reader.Value; } } reader.MoveToElement(); using (IMLReader iTmp = new IMLReader(null, reader.ReadInnerXml())) { string uid = Guid.NewGuid().ToString(); Interface.Instantiators [uid] = new ItemTemplate(iTmp.RootType, iTmp.GetLoader(), dataType, datas); itemTemplateIds.Add(new string[] { dataType, uid, datas }); } } } if (!inlineTemplate) { reader.il.Emit(OpCodes.Ldloc_0); //Load this templateControl ref if (string.IsNullOrEmpty(templatePath)) { reader.il.Emit(OpCodes.Ldnull); //default template loading } else { reader.il.Emit(OpCodes.Ldarg_1); //load currentInterface reader.il.Emit(OpCodes.Ldstr, templatePath); //Load template path string reader.il.Emit(OpCodes.Callvirt, //call Interface.Load(path) typeof(Interface).GetMethod("Load", BindingFlags.Instance | BindingFlags.Public)); } reader.il.Emit(OpCodes.Callvirt, //load template crowType.GetMethod("loadTemplate", BindingFlags.Instance | BindingFlags.NonPublic)); } foreach (string[] iTempId in itemTemplateIds) { reader.il.Emit(OpCodes.Ldloc_0); //load TempControl ref reader.il.Emit(OpCodes.Ldfld, //load ItemTemplates dic field typeof(TemplatedGroup).GetField("ItemTemplates")); reader.il.Emit(OpCodes.Ldstr, iTempId[0]); //load key reader.il.Emit(OpCodes.Ldstr, iTempId[1]); //load value reader.il.Emit(OpCodes.Callvirt, typeof(Interface).GetMethod("GetItemTemplate")); reader.il.Emit(OpCodes.Callvirt, typeof(Dictionary <string, ItemTemplate>).GetMethod("set_Item", new Type[] { typeof(string), typeof(ItemTemplate) })); if (!string.IsNullOrEmpty(iTempId [2])) { //expand delegate creation reader.il.Emit(OpCodes.Ldloc_0); //load TempControl ref reader.il.Emit(OpCodes.Ldfld, //load ItemTemplates dic field typeof(TemplatedGroup).GetField("ItemTemplates")); reader.il.Emit(OpCodes.Ldstr, iTempId [0]); //load key reader.il.Emit(OpCodes.Callvirt, typeof(Dictionary <string, ItemTemplate>).GetMethod("get_Item", new Type[] { typeof(string) })); reader.il.Emit(OpCodes.Ldloc_0); //load root of treeView reader.il.Emit(OpCodes.Callvirt, typeof(ItemTemplate).GetMethod("CreateExpandDelegate")); } } } } #endregion using (IMLReader reader = new IMLReader(il, tmpXml)){ reader.Read(); #region Styling and default values loading if (reader.HasAttributes) { string style = reader.GetAttribute("Style"); if (!string.IsNullOrEmpty(style)) { PropertyInfo pi = crowType.GetProperty("Style"); CompilerServices.EmitSetValue(reader.il, pi, style); } } reader.il.Emit(OpCodes.Ldloc_0); reader.il.Emit(OpCodes.Callvirt, typeof(GraphicObject).GetMethod("loadDefaultValues")); #endregion #region Attributes reading if (reader.HasAttributes) { MethodInfo miAddBinding = typeof(GraphicObject).GetMethod("BindMember"); while (reader.MoveToNextAttribute()) { if (reader.Name == "Style") { continue; } MemberInfo mi = crowType.GetMember(reader.Name).FirstOrDefault(); if (mi == null) { throw new Exception("Member '" + reader.Name + "' not found in " + crowType.Name); } if (mi.MemberType == MemberTypes.Event) { CompilerServices.emitBindingCreation(reader.il, reader.Name, reader.Value); continue; } PropertyInfo pi = mi as PropertyInfo; if (pi == null) { throw new Exception("Member '" + reader.Name + "' not found in " + crowType.Name); } if (reader.Value.StartsWith("{")) { CompilerServices.emitBindingCreation(reader.il, reader.Name, reader.Value.Substring(1, reader.Value.Length - 2)); } else { CompilerServices.EmitSetValue(reader.il, pi, reader.Value); } } reader.MoveToElement(); } #endregion if (reader.IsEmptyElement) { reader.il.Emit(OpCodes.Pop); //pop saved ref to current object return; } readChildren(reader, crowType); } il.Emit(OpCodes.Pop); //pop saved ref to current object }
/// <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); }
/// <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); } } } } }
/// <summary> /// Creates the expand delegate. /// </summary> /// <param name="host">Host.</param> public void CreateExpandDelegate(TemplatedGroup host) { Type dataType = null; //if (host.DataTest == "TypeOf"){ dataType = CompilerServices.tryGetType(strDataType); // if (dataType == null) { // Debug.WriteLine ("ItemTemplate error: DataType not found: {0}.", strDataType); // return; // } // } Type tmpGrpType = typeof(TemplatedGroup); Type evtType = typeof(EventHandler); //PropertyInfo piData = tmpGrpType.GetProperty ("Data"); MethodInfo evtInvoke = evtType.GetMethod("Invoke"); ParameterInfo [] evtParams = evtInvoke.GetParameters(); Type handlerArgsType = evtParams [1].ParameterType; Type [] args = { CompilerServices.TObject, CompilerServices.TObject, handlerArgsType }; #region Expand dyn meth //DM is bound to templatedGroup root (arg0) //arg1 is the sender of the expand event DynamicMethod dm = new DynamicMethod("dyn_expand_" + fetchMethodName, typeof(void), args, typeof(TemplatedGroup), true); System.Reflection.Emit.Label gotoEnd; System.Reflection.Emit.Label ifDataIsNull; System.Reflection.Emit.Label gotoItemsContainerNotFound; ILGenerator il = dm.GetILGenerator(256); il.DeclareLocal(typeof(GraphicObject)); gotoEnd = il.DefineLabel(); ifDataIsNull = il.DefineLabel(); gotoItemsContainerNotFound = il.DefineLabel(); il.Emit(OpCodes.Ldarg_1); //load sender of expand event il.Emit(OpCodes.Ldstr, "ItemsContainer"); //load name to find il.Emit(OpCodes.Callvirt, CompilerServices.miFindByName); il.Emit(OpCodes.Stloc_0); //save items container as loc0 //ensure ItemsContainer is not null il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Brfalse, gotoItemsContainerNotFound); //check that node is not already expanded il.Emit(OpCodes.Ldarg_0); //push root TemplatedGroup into the stack il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Call, CompilerServices.miIsAlreadyExpanded); il.Emit(OpCodes.Brtrue, gotoEnd); // il.Emit (OpCodes.Ldloc_0); // il.Emit (OpCodes.Callvirt, piData.GetGetMethod ()); // il.Emit (OpCodes.Brfalse, ifDataIsNull); // il.Emit (OpCodes.Br, gotoEnd); // il.MarkLabel(ifDataIsNull); //copy the ref of ItemTemplates list TODO: maybe find another way to share it among the nodes? // FieldInfo fiTemplates = tmpGrpType.GetField("ItemTemplates"); // il.Emit (OpCodes.Ldloc_0); // il.Emit (OpCodes.Ldarg_0); // il.Emit (OpCodes.Ldfld, fiTemplates); // il.Emit (OpCodes.Stfld, fiTemplates); //call 'fetchMethodName' from the dataSource to build the sub nodes list //il.Emit (OpCodes.Ldarg_0);//load root templatedGroop il.Emit(OpCodes.Ldarg_0); //push root TemplatedGroup into the stack il.Emit(OpCodes.Ldarg_1); //load sender node of expand il.Emit(OpCodes.Callvirt, CompilerServices.miGetDataSource); //get the dataSource of the sender if (fetchMethodName != "self") //special keyword self allows the use of recurent list<<< { if (dataType == null) { //dataTest was not = TypeOF, so we have to get the type of data //dynamically and fetch il.Emit(OpCodes.Ldstr, fetchMethodName); il.Emit(OpCodes.Callvirt, CompilerServices.miGetDataTypeAndFetch); } else { emitGetSubData(il, dataType); } } //set 'return' from the fetch method as 'data' of the list //il.Emit (OpCodes.Callvirt, piData.GetSetMethod ()); il.Emit(OpCodes.Ldloc_0); //load second arg of loadPage, the sender node il.Emit(OpCodes.Ldstr, dataTest); //load 3rd arg, dataTest kind on subitems il.Emit(OpCodes.Callvirt, CompilerServices.miLoadPage); il.Emit(OpCodes.Br, gotoEnd); il.MarkLabel(gotoItemsContainerNotFound); il.EmitWriteLine("ItemsContainer not found in ItemTemplate for " + host.ToString()); il.MarkLabel(gotoEnd); il.Emit(OpCodes.Ret); Expand = (EventHandler)dm.CreateDelegate(evtType, host); #endregion #region Items counting dyn method //dm is unbound, arg0 is instance of Item container to expand dm = new DynamicMethod("dyn_count_" + fetchMethodName, typeof(bool), new Type[] { CompilerServices.TObject }, true); il = dm.GetILGenerator(256); //get the dataSource of the arg0 il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Callvirt, CompilerServices.miGetDataSource); if (fetchMethodName != "self") //special keyword self allows the use of recurent list<<< { if (dataType == null) { //dataTest was not = TypeOF, so we have to get the type of data //dynamically and fetch il.Emit(OpCodes.Ldstr, fetchMethodName); il.Emit(OpCodes.Callvirt, CompilerServices.miGetDataTypeAndFetch); } else { emitGetSubData(il, dataType); } } il.Emit(OpCodes.Callvirt, CompilerServices.miGetColCount); il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Cgt); il.Emit(OpCodes.Ret); HasSubItems = (BooleanTestOnInstance)dm.CreateDelegate(typeof(BooleanTestOnInstance)); #endregion }