From ae08f9c696e2470e747d138ecf2b8c7d643e50a2 Mon Sep 17 00:00:00 2001 From: jpbruyere Date: Mon, 12 Oct 2015 13:53:37 +0200 Subject: [PATCH] Bindings clearance, code clean --- Tests/GOLIBTests.cs | 4 +- src/CompilerServices/CompilerServices.cs | 573 +++-------------------- src/GraphicObjects/GraphicObject.cs | 143 +++--- src/Interface.cs | 47 -- 4 files changed, 146 insertions(+), 621 deletions(-) diff --git a/Tests/GOLIBTests.cs b/Tests/GOLIBTests.cs index 13576b24..508acc2d 100644 --- a/Tests/GOLIBTests.cs +++ b/Tests/GOLIBTests.cs @@ -44,8 +44,8 @@ namespace test "testSpinner.goml", "testPopper.goml", "testGroupBox.goml", - "testWindow.goml", - "testMsgBox.goml", +// "testWindow.goml", +// "testMsgBox.goml", "testGrid.goml", "testMeter.goml", // "testCombobox.goml", diff --git a/src/CompilerServices/CompilerServices.cs b/src/CompilerServices/CompilerServices.cs index 0d13d7bf..07afdaea 100644 --- a/src/CompilerServices/CompilerServices.cs +++ b/src/CompilerServices/CompilerServices.cs @@ -10,65 +10,91 @@ using System.Runtime.CompilerServices; namespace go { - public enum BindingType + public class MemberReference { - Handler, - DynamicHandler, - PropertyBinding - } - public class Binding{ - public MemberInfo SourceMember; - public string Expression; + public object Instance; + public MemberInfo Member; - public PropertyInfo Property { get { return SourceMember as PropertyInfo; } } - public EventInfo Event { get { return SourceMember as EventInfo; } } + public PropertyInfo Property { get { return Member as PropertyInfo; } } + public FieldInfo Field { get { return Member as FieldInfo; } } + public EventInfo Event { get { return Member as EventInfo; } } + public MethodInfo Method { get { return Member as MethodInfo; } } - public Binding(){ + public MemberReference(){ } - public Binding(MemberInfo _sourceMember, string _expression) + public MemberReference(object _instance, MemberInfo _member = null) { - SourceMember = _sourceMember; - Expression = _expression; + Instance = _instance; + Member = _member; + } + public bool FindMember(string _memberName) + { + Type t = Instance.GetType (); + Member = t.GetMember (_memberName).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 string.IsNullOrEmpty(_memberName) ? false : true; } } + public class Binding{ + static int bindingCpt = 0; + string dynMethodId = ""; + public string NewDynMethodId { + get { + if (!string.IsNullOrEmpty (dynMethodId)) + return dynMethodId; + dynMethodId = "dynHandle_" + bindingCpt; + bindingCpt++; + return dynMethodId; + } + } + public string DynMethodId { + get { return dynMethodId; } + } + - public class ResolvedBinding - { - public object Target; - public MemberInfo Member; + public MemberReference Source; + public MemberReference Target; - public Binding Binding; + public string Expression; - public ResolvedBinding(){ - } - public ResolvedBinding(Binding _binding){ - Binding = _binding; + #region CTOR + public Binding(){} + public Binding(MemberReference _source, string _expression) + { + Source = _source; + Expression = _expression; } + #endregion - public bool FindTarget(GraphicObject source){ + public bool FindTarget(){ string member = null; //if binding exp = '{}' => binding is done on datasource - if (string.IsNullOrEmpty (Binding.Expression)) { - Target = source; - Member = null; + if (string.IsNullOrEmpty (Expression)) { + Target = new MemberReference (Source.Instance); return true; } - //if (Binding.SourceMember.MemberType == MemberTypes.Event) - - string[] bindingExp = Binding.Expression.Split ('/'); + string[] bindingExp = Expression.Split ('/'); if (bindingExp.Length == 1) { //datasource binding - Target = source.DataSource; + Target = new MemberReference((Source.Instance as GraphicObject).DataSource); member = bindingExp [0]; } else { int ptr = 0; - ILayoutable tmp = source; + ILayoutable tmp = Source.Instance as ILayoutable; if (string.IsNullOrEmpty (bindingExp [0])) { //if exp start with '/' => Graphic tree parsing start at top container - tmp = source.TopContainer as ILayoutable; + tmp = tmp.TopContainer as ILayoutable; ptr++; } while (ptr < bindingExp.Length - 1) { @@ -79,7 +105,7 @@ namespace go else if (bindingExp [ptr] == ".") { if (ptr > 0) throw new Exception ("Syntax error in binding, './' may only appear in first position"); - tmp = source; + tmp = Source.Instance as ILayoutable; }else tmp = (tmp as GraphicObject).FindByName (bindingExp [ptr]); ptr++; @@ -94,486 +120,33 @@ namespace go member = bindTrg [1]; } else throw new Exception ("Syntax error in binding, expected 'go dot member'"); - - Target = tmp; - } - if (Target == null) { - Debug.WriteLine ("Binding Source is null: " + Binding.Expression); - return false; - } - Type targetType = Target.GetType (); - Member = targetType.GetMember (member).FirstOrDefault (); - #region search for extensions methods if member not found in type - if (Member == null && !string.IsNullOrEmpty(member)) - { - Assembly a = Assembly.GetExecutingAssembly(); - Member = CompilerServices.GetExtensionMethods(a, targetType).FirstOrDefault(); + Target = new MemberReference(tmp); } - #endregion - - if (member == null) { - Debug.WriteLine ("Binding member not found: " + member); + if (Target == null) { + Debug.WriteLine ("Binding Source is null: " + Expression); return false; } - return true; + if (Target.FindMember (member)) + return true; + + Debug.WriteLine ("Binding member not found: " + member); + return false; } - } - - public static class CompilerServices2 - { - static int dynHandleCpt = 0; - /// - /// Compile events expression in GOML attributes - /// - /// Event binding details - public static void ResolveBinding(DynAttribute es) + public void Reset() { - Type srcType = es.Source.GetType (); - - #region Retrieve EventHandler parameter type - EventInfo ei = srcType.GetEvent (es.MemberName); - MethodInfo invoke = ei.EventHandlerType.GetMethod ("Invoke"); - ParameterInfo[] pars = invoke.GetParameters (); - - Type handlerArgsType = pars [1].ParameterType; - #endregion - - Type[] args = {typeof(object), handlerArgsType}; - DynamicMethod dm = new DynamicMethod("dynHandle_" + dynHandleCpt, - typeof(void), - args, - srcType.Module); - - es.Source.DynamicMethodIds.Add (dynHandleCpt); - - dynHandleCpt++; - - #region IL generation - ILGenerator il = dm.GetILGenerator(256); - - string src = es.Value.Trim(); - - if (! (src.StartsWith("{") || src.EndsWith ("}"))) - throw new Exception (string.Format("GOML:Malformed {0} Event handler: {1}", es.MemberName, es.Value)); - - src = src.Substring (1, src.Length - 2); - string[] srcLines = src.Split (new char[] { ';' }); - - foreach (string srcLine in srcLines) { - string statement = srcLine.Trim (); - - string[] operandes = statement.Split (new char[] { '=' }); - if (operandes.Length < 2) //not an affectation - { - continue; - } - string lop = operandes [0].Trim (); - string rop = operandes [operandes.Length-1].Trim (); - - #region LEFT OPERANDES - GraphicObject lopObj = es.Source; //default left operand base object is - //the first arg (object sender) of the event handler - - string[] lopParts = lop.Split (new char[] { '.' }); - if (lopParts.Length == 2) {//should search also for member of es.Source - lopObj = es.Source.FindByName (lopParts [0]); - if (lopObj==null) - throw new Exception (string.Format("GOML:Unknown name: {0}", lopParts[0])); - //TODO: should create private member holding ref of lopObj, and emit - //a call to FindByName(lopObjName) during #ctor or in a onLoad func or evt handler - throw new Exception (string.Format("GOML:obj tree ref not yet implemented", lopParts[0])); - }else - il.Emit(OpCodes.Ldarg_0); //load sender ref onto the stack - - int i = lopParts.Length -1; - - MemberInfo lopMbi = lopObj.GetType().GetMember (lopParts[i])[0]; - OpCode lopSetOC; - dynamic lopSetMbi; - Type lopT = null; - switch (lopMbi.MemberType) { - case MemberTypes.Property: - PropertyInfo lopPi = srcType.GetProperty (lopParts[i]); - MethodInfo dstMi = lopPi.GetSetMethod (); - lopT = lopPi.PropertyType; - lopSetMbi = dstMi; - lopSetOC = OpCodes.Callvirt; - break; - case MemberTypes.Field: - FieldInfo dstFi = srcType.GetField(lopParts[i]); - lopT = dstFi.FieldType; - lopSetMbi = dstFi; - lopSetOC = OpCodes.Stfld; - break; - default: - throw new Exception (string.Format("GOML:member type not handle: {0}", lopParts[i])); - } - #endregion - - #region RIGHT OPERANDES - if (rop.StartsWith("\'")){ - if (!rop.EndsWith("\'")) - throw new Exception (string.Format - ("GOML:malformed string constant in handler: {0}", rop)); - string strcst = rop.Substring (1, rop.Length - 2); - - il.Emit(OpCodes.Ldstr,strcst); - - }else{ - //search for a static field in left operand type named 'rop name' - FieldInfo ropFi = lopT.GetField (rop, BindingFlags.Static|BindingFlags.Public); - if (ropFi != null) - { - il.Emit (OpCodes.Ldsfld, ropFi); - }else{ - //search if parsing methods are present - MethodInfo lopTryParseMi = lopT.GetMethod("TryParse"); - - } - } - - #endregion - - //emit left operand assignment - il.Emit(lopSetOC, lopSetMbi); - } + Target = null; + dynMethodId = ""; + } + } - il.Emit(OpCodes.Ret); - #endregion - Delegate del = dm.CreateDelegate(ei.EventHandlerType); - MethodInfo addHandler = ei.GetAddMethod (); - addHandler.Invoke(es.Source, new object[] {del}); - } - - } public static class CompilerServices { - public static void CreateBindingHandler() - { - } - static int dynHandleCpt = 0; - /// - /// Compile events expression in GOML attributes - /// - /// Event binding details - public static void CompileEventSource(DynAttribute es) - { - Type srcType = es.Source.GetType (); - - #region Retrieve EventHandler parameter type - EventInfo ei = srcType.GetEvent (es.MemberName); - MethodInfo invoke = ei.EventHandlerType.GetMethod ("Invoke"); - ParameterInfo[] pars = invoke.GetParameters (); - - Type handlerArgsType = pars [1].ParameterType; - #endregion - - Type[] args = {typeof(object), handlerArgsType}; - DynamicMethod dm = new DynamicMethod("dynHandle", - typeof(void), - args, - srcType.Module); - - #region IL generation - ILGenerator il = dm.GetILGenerator(256); - - string src = es.Value.Trim(); - - if (! (src.StartsWith("{") || src.EndsWith ("}"))) - throw new Exception (string.Format("GOML:Malformed {0} Event handler: {1}", es.MemberName, es.Value)); - - src = src.Substring (1, src.Length - 2); - string[] srcLines = src.Split (new char[] { ';' }); - - foreach (string srcLine in srcLines) { - string statement = srcLine.Trim (); - - string[] operandes = statement.Split (new char[] { '=' }); - if (operandes.Length < 2) //not an affectation - { - continue; - } - string lop = operandes [0].Trim (); - string rop = operandes [operandes.Length-1].Trim (); - - #region LEFT OPERANDES - GraphicObject lopObj = es.Source; //default left operand base object is - //the first arg (object sender) of the event handler - - string[] lopParts = lop.Split (new char[] { '.' }); - if (lopParts.Length == 2) {//should search also for member of es.Source - lopObj = es.Source.FindByName (lopParts [0]); - if (lopObj==null) - throw new Exception (string.Format("GOML:Unknown name: {0}", lopParts[0])); - //TODO: should create private member holding ref of lopObj, and emit - //a call to FindByName(lopObjName) during #ctor or in a onLoad func or evt handler - throw new Exception (string.Format("GOML:obj tree ref not yet implemented", lopParts[0])); - }else - il.Emit(OpCodes.Ldarg_0); //load sender ref onto the stack - - int i = lopParts.Length -1; - - MemberInfo lopMbi = lopObj.GetType().GetMember (lopParts[i])[0]; - OpCode lopSetOC; - dynamic lopSetMbi; - Type lopT = null; - switch (lopMbi.MemberType) { - case MemberTypes.Property: - PropertyInfo lopPi = srcType.GetProperty (lopParts[i]); - MethodInfo dstMi = lopPi.GetSetMethod (); - lopT = lopPi.PropertyType; - lopSetMbi = dstMi; - lopSetOC = OpCodes.Callvirt; - break; - case MemberTypes.Field: - FieldInfo dstFi = srcType.GetField(lopParts[i]); - lopT = dstFi.FieldType; - lopSetMbi = dstFi; - lopSetOC = OpCodes.Stfld; - break; - default: - throw new Exception (string.Format("GOML:member type not handle: {0}", lopParts[i])); - } - #endregion - - #region RIGHT OPERANDES - if (rop.StartsWith("\'")){ - if (!rop.EndsWith("\'")) - throw new Exception (string.Format - ("GOML:malformed string constant in handler: {0}", rop)); - string strcst = rop.Substring (1, rop.Length - 2); - - il.Emit(OpCodes.Ldstr,strcst); - - }else{ - //search for a static field in left operand type named 'rop name' - FieldInfo ropFi = lopT.GetField (rop, BindingFlags.Static|BindingFlags.Public); - if (ropFi != null) - { - il.Emit (OpCodes.Ldsfld, ropFi); - }else{ - //search if parsing methods are present - MethodInfo lopTryParseMi = lopT.GetMethod("TryParse"); - //TODO - } - } - - #endregion - - //emit left operand assignment - il.Emit(lopSetOC, lopSetMbi); - } - - il.Emit(OpCodes.Ret); - - #endregion - - Delegate del = dm.CreateDelegate(ei.EventHandlerType); - MethodInfo addHandler = ei.GetAddMethod (); - addHandler.Invoke(es.Source, new object[] {del}); - } - - /// - /// Resolves GOML property bindings afler loading - /// - /// Binding details - /// Data source for binding - public static void ResolveBinding(DynAttribute binding, object _source) - { - object srcGO = null; - string statement = binding.Value; - - if (statement.StartsWith ("/"))//binding is done in graphic object tree, _source param is ignore - srcGO = binding.Source; - else - srcGO = _source; - - string[] bindingExp = binding.Value.Split ('/'); - - if (bindingExp.Length > 1){ - int i = 0; - srcGO = binding.Source; //starts parsing from current GO - while (i < bindingExp.Length - 1) { - if (bindingExp [i] == "..") - srcGO = (srcGO as ILayoutable).Parent as GraphicObject; - else - srcGO = (srcGO as GraphicObject).FindByName (bindingExp [i]); - i++; - } - string[] bindTrg = bindingExp [i].Split ('.'); - - if (bindTrg.Length == 2) { - srcGO = (srcGO as GraphicObject).FindByName (bindTrg [0]); - statement = bindTrg [1]; - } else - throw new Exception ("Syntax error in binding, expected 'go dot member'"); - } - - if (srcGO == null) { - Debug.WriteLine ("Invalid Binding Source: " + binding.Value); - return; - } - Type srcType = srcGO.GetType (); - Type dstType = binding.Source.GetType (); - - MemberInfo miSrc = srcType.GetMember (statement).FirstOrDefault (); - MemberInfo miDst = dstType.GetMember (binding.MemberName).FirstOrDefault (); - - object srcVal = null; //value in source member - - #region search for extensions methods if member not found in type - if (miSrc == null && !string.IsNullOrEmpty(statement)) - { - Assembly a = Assembly.GetExecutingAssembly(); - miSrc = CompilerServices.GetExtensionMethods(a, srcType).FirstOrDefault(); - } - #endregion - - #region initialize target with actual value - - if (string.IsNullOrEmpty(binding.Value)) - srcVal = srcGO;//if no member is provided for binding, source raw value is taken - else if (miSrc != null){ - if (miSrc.MemberType == MemberTypes.Property) - srcVal = (miSrc as PropertyInfo).GetGetMethod ().Invoke (srcGO, null); - else if (miSrc.MemberType == MemberTypes.Field) - srcVal = (miSrc as FieldInfo).GetValue (srcGO); - else if (miSrc.MemberType == MemberTypes.Method){ - MethodInfo mthSrc = miSrc as MethodInfo; - if (mthSrc.IsDefined(typeof(ExtensionAttribute), false)) - srcVal = mthSrc.Invoke(null, new object[] {srcGO}); - else - srcVal = mthSrc.Invoke(srcGO, null); - }else - throw new Exception ("unandled source member type for binding"); - } -// if (miSrc != null){ - if (miDst.MemberType == MemberTypes.Property) { - PropertyInfo piDst = miDst as PropertyInfo; - //TODO: handle other dest type conversions - if (piDst.PropertyType == typeof(string)){ - if (srcVal != null) - srcVal = srcVal.ToString (); - } - piDst.GetSetMethod ().Invoke (binding.Source, new object[] { srcVal }); - } else if (miDst.MemberType == MemberTypes.Field) { - FieldInfo fiDst = miDst as FieldInfo; - if (fiDst.FieldType == typeof(string)) - srcVal = srcVal.ToString (); - fiDst.SetValue (binding.Source, srcVal ); - }else - throw new Exception("unandled destination member type for binding"); -// } - #endregion - - #region Retrieve EventHandler parameter type - EventInfo ei = srcType.GetEvent ("ValueChanged"); - if (ei == null) - return; //no dynamic update if ValueChanged interface is not implemented - - MethodInfo evtInvoke = ei.EventHandlerType.GetMethod ("Invoke"); - ParameterInfo[] evtParams = evtInvoke.GetParameters (); - Type handlerArgsType = evtParams [1].ParameterType; - - #endregion - - - Type[] args = {typeof(object), handlerArgsType}; - DynamicMethod dm = new DynamicMethod("dynHandle_" + dynHandleCpt, - typeof(void), - args, - srcType.Module, true); - - (binding.Source as GraphicObject).DynamicMethodIds.Add (dynHandleCpt); - - dynHandleCpt++; - - //register target object reference - int dstIdx = Interface.Reference(binding.Source); - - #region IL generation - ILGenerator il = dm.GetILGenerator(256); - - System.Reflection.Emit.Label labFailed = il.DefineLabel(); - System.Reflection.Emit.Label labContinue = il.DefineLabel(); - - #region test if valueChange event is the correct one - il.Emit (OpCodes.Ldstr, statement); - //push name from arg - il.Emit(OpCodes.Ldarg_1); - FieldInfo fiMbName = typeof(ValueChangeEventArgs).GetField("MemberName"); - il.Emit(OpCodes.Ldfld, fiMbName); - MethodInfo miStrEqu = typeof(string).GetMethod("op_Inequality", new Type[] {typeof(string),typeof(string)}); - il.Emit(OpCodes.Call, miStrEqu); - il.Emit(OpCodes.Brfalse_S, labContinue); - il.Emit(OpCodes.Br_S, labFailed); - il.MarkLabel(labContinue); - #endregion - -// string[] srcLines = binding.Value.Trim().Split (new char[] { ';' }); -// foreach (string srcLine in srcLines) { - //MethodInfo infoWriteLine = typeof(System.Diagnostics.Debug).GetMethod("WriteLine", new Type[] { typeof(string) }); - - - //load target ref onto the stack - FieldInfo fiRefs = typeof(Interface).GetField("References"); - il.Emit(OpCodes.Ldsfld, fiRefs); - il.Emit(OpCodes.Ldc_I4, dstIdx); - MethodInfo miGetRef = Interface.References.GetType().GetMethod("get_Item"); - il.Emit(OpCodes.Callvirt, miGetRef); - il.Emit(OpCodes.Isinst, dstType); - - //push new value - il.Emit(OpCodes.Ldarg_1); - FieldInfo fiNewValue = typeof(ValueChangeEventArgs).GetField("NewValue"); - il.Emit(OpCodes.Ldfld, fiNewValue); - - //Target is expected always to be a Property - PropertyInfo piTarget = dstType.GetProperty(binding.MemberName); - - //type of the source value - Type srcValueType = null; - - //member info of the source value - MemberInfo miSrcVal = miSrc; - - //this allow memberless binding with only a name passed as MemberName - //the type of the source value is determined by the destination member - if (miSrcVal == null) - miSrcVal = miDst; - - if (miSrcVal.MemberType == MemberTypes.Property) - srcValueType = (miSrcVal as PropertyInfo).PropertyType; - else if (miSrcVal.MemberType == MemberTypes.Field) - srcValueType = (miSrcVal as FieldInfo).FieldType; - else - throw new Exception("unandled source member type for binding"); - - if (!srcValueType.IsValueType) - il.Emit(OpCodes.Castclass, srcValueType); - else if (piTarget.PropertyType != srcValueType) - il.Emit(OpCodes.Callvirt, GetConvertMethod( piTarget.PropertyType )); - else - il.Emit(OpCodes.Unbox_Any, piTarget.PropertyType); - - il.Emit(OpCodes.Callvirt, piTarget.GetSetMethod()); - - il.MarkLabel(labFailed); - il.Emit(OpCodes.Ret); - - #endregion - - Delegate del = dm.CreateDelegate(ei.EventHandlerType); - MethodInfo addHandler = ei.GetAddMethod (); - addHandler.Invoke(srcGO, new object[] {del}); - } - #region conversions internal static MethodInfo GetConvertMethod( Type targetType ) diff --git a/src/GraphicObjects/GraphicObject.cs b/src/GraphicObjects/GraphicObject.cs index 7ebcaf61..505e85a9 100644 --- a/src/GraphicObjects/GraphicObject.cs +++ b/src/GraphicObjects/GraphicObject.cs @@ -23,7 +23,13 @@ namespace go { public class GraphicObject : IXmlSerializable, ILayoutable, IValueChange { - internal List DynamicMethodIds = new List (); + internal List DynamicMethodIds + { + get { return Bindings. + Where(bi=>!string.IsNullOrEmpty(bi.DynMethodId)). + Select (b => b.DynMethodId).ToList (); + } + } internal List Bindings = new List (); #region IValueChange implementation @@ -790,38 +796,36 @@ namespace go public virtual void ResolveBindings() { - List resolved = new List (); + List resolved = new List (); foreach (Binding b in Bindings) { - if (b.SourceMember.MemberType == MemberTypes.Event) { + if (b.Source.Member.MemberType == MemberTypes.Event) { if (b.Expression.StartsWith("{")){ CompileEventSource(b); continue; } } - ResolvedBinding rb = new ResolvedBinding (b); - if (!rb.FindTarget (this)) + if (!b.FindTarget ()) continue; - if (rb.Binding.SourceMember.MemberType == MemberTypes.Event) { + if (b.Source.Member.MemberType == MemberTypes.Event) { //register handler for event - MethodInfo mi = rb.Member as MethodInfo; - if (mi == null) { - Debug.WriteLine ("Handler Method not found: " + rb.Binding.Expression); + if (b.Target.Method == null) { + Debug.WriteLine ("Handler Method not found: " + b.Expression); continue; } - MethodInfo addHandler = rb.Binding.Event.GetAddMethod (); - Delegate del = Delegate.CreateDelegate (rb.Binding.Event.EventHandlerType, rb.Target, mi); + MethodInfo addHandler = b.Source.Event.GetAddMethod (); + Delegate del = Delegate.CreateDelegate (b.Source.Event.EventHandlerType, b.Target.Instance, b.Target.Method); addHandler.Invoke (this, new object[] { del }); continue; } - resolved.Add (rb); + resolved.Add (b); } //group;only one dynMethods by target (valuechanged event source) //changed value name tested in switch - IEnumerable groupedByTarget = resolved.GroupBy (g => g.Target, g => g, (k, g) => g.ToArray ()); - foreach (ResolvedBinding[] grouped in groupedByTarget) { + IEnumerable groupedByTarget = resolved.GroupBy (g => g.Target.Instance, g => g, (k, g) => g.ToArray ()); + foreach (Binding[] grouped in groupedByTarget) { int i = 0; - Type targetType = grouped[0].Target.GetType(); + Type targetType = grouped[0].Target.Instance.GetType(); Type sourceType = this.GetType(); DynamicMethod dm = null; @@ -837,6 +841,8 @@ namespace go LocalBuilder lbMemberName = null; LocalBuilder lbValue = null; + + #region Retrieve EventHandler parameter type EventInfo ei = targetType.GetEvent ("ValueChanged"); //no dynamic update if ValueChanged interface is not implemented @@ -846,7 +852,7 @@ namespace go Type handlerArgsType = evtParams [1].ParameterType; Type[] args = {typeof(object), typeof(object),handlerArgsType}; - dm = new DynamicMethod("dynHandle", + dm = new DynamicMethod(grouped[0].NewDynMethodId, typeof(void), args, sourceType); @@ -881,33 +887,33 @@ namespace go #endregion i = 0; - foreach (ResolvedBinding rb in grouped) { + foreach (Binding b in grouped) { #region initialize target with actual value object targetValue = null; - if (rb.Member != null){ - if (rb.Member.MemberType == MemberTypes.Property) - targetValue = (rb.Member as PropertyInfo).GetGetMethod ().Invoke (rb.Target, null); - else if (rb.Member.MemberType == MemberTypes.Field) - targetValue = (rb.Member as FieldInfo).GetValue (rb.Target); - else if (rb.Member.MemberType == MemberTypes.Method){ - MethodInfo mthSrc = rb.Member as MethodInfo; + 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[] {rb.Target}); + targetValue = mthSrc.Invoke(null, new object[] {b.Target.Instance}); else - targetValue = mthSrc.Invoke(rb.Target, null); + targetValue = mthSrc.Invoke(b.Target.Instance, null); }else throw new Exception ("unandled source member type for binding"); - }else if (string.IsNullOrEmpty(rb.Binding.Expression)) + }else if (string.IsNullOrEmpty(b.Expression)) targetValue= grouped [0].Target;//empty binding exp=> bound to target object by default //TODO: handle other dest type conversions - if (rb.Binding.Property.PropertyType == typeof(string)){ + if (b.Source.Property.PropertyType == typeof(string)){ if (targetValue == null){ //set default value }else targetValue = targetValue.ToString (); } - rb.Binding.Property.GetSetMethod ().Invoke (this, new object[] { targetValue }); + b.Source.Property.GetSetMethod ().Invoke (this, new object[] { targetValue }); #endregion //if no dyn update, skip jump table @@ -915,10 +921,10 @@ namespace go continue; il.Emit (OpCodes.Ldloc_0); - if (rb.Member != null) - il.Emit (OpCodes.Ldstr, rb.Member.Name); + if (b.Target.Member != null) + il.Emit (OpCodes.Ldstr, b.Target.Member.Name); else - il.Emit (OpCodes.Ldstr, rb.Binding.Expression); + il.Emit (OpCodes.Ldstr, b.Expression); il.Emit (OpCodes.Callvirt, stringEquals); il.Emit (OpCodes.Brtrue, jumpTable[i]); i++; @@ -930,7 +936,7 @@ namespace go il.Emit (OpCodes.Br, endMethod); i = 0; - foreach (ResolvedBinding rb in grouped) { + foreach (Binding b in grouped) { il.MarkLabel (jumpTable [i]); il.Emit(OpCodes.Ldloc_1); @@ -938,24 +944,24 @@ namespace go //by default, target value type is deducted from source member type to allow //memberless binding, if targetMember exists, it will be used to determine target //value type for conversion - Type targetValueType = rb.Binding.Property.PropertyType; - if (rb.Member != null) { - if (rb.Member.MemberType == MemberTypes.Property) - targetValueType = (rb.Member as PropertyInfo).PropertyType; - else if (rb.Member.MemberType == MemberTypes.Field) - targetValueType = (rb.Member as FieldInfo).FieldType; + Type targetValueType = b.Source.Property.PropertyType; + if (b.Target.Member != null) { + if (b.Target.Member.MemberType == MemberTypes.Property) + targetValueType = b.Target.Property.PropertyType; + else if (b.Target.Member.MemberType == MemberTypes.Field) + targetValueType = b.Target.Field.FieldType; else throw new Exception ("unhandle target member type in binding"); } if (!targetValueType.IsValueType) il.Emit(OpCodes.Castclass, targetValueType); - else if (rb.Binding.Property.PropertyType != targetValueType) - il.Emit(OpCodes.Callvirt, CompilerServices.GetConvertMethod( rb.Binding.Property.PropertyType )); + else if (b.Source.Property.PropertyType != targetValueType) + il.Emit(OpCodes.Callvirt, CompilerServices.GetConvertMethod( b.Source.Property.PropertyType )); else - il.Emit(OpCodes.Unbox_Any, rb.Binding.Property.PropertyType); + il.Emit(OpCodes.Unbox_Any, b.Source.Property.PropertyType); - il.Emit(OpCodes.Callvirt, rb.Binding.Property.GetSetMethod()); + il.Emit(OpCodes.Callvirt, b.Source.Property.GetSetMethod()); il.Emit (OpCodes.Br, endMethod); i++; @@ -966,7 +972,7 @@ namespace go Delegate del = dm.CreateDelegate(ei.EventHandlerType, this); MethodInfo addHandler = ei.GetAddMethod (); - addHandler.Invoke(grouped [0].Target, new object[] {del}); + addHandler.Invoke(grouped [0].Target.Instance, new object[] {del}); } } /// @@ -978,13 +984,13 @@ namespace go Type sourceType = this.GetType(); #region Retrieve EventHandler parameter type - MethodInfo evtInvoke = binding.Event.EventHandlerType.GetMethod ("Invoke"); + MethodInfo evtInvoke = binding.Source.Event.EventHandlerType.GetMethod ("Invoke"); ParameterInfo[] evtParams = evtInvoke.GetParameters (); Type handlerArgsType = evtParams [1].ParameterType; #endregion Type[] args = {typeof(object), typeof(object),handlerArgsType}; - DynamicMethod dm = new DynamicMethod("dynHandle", + DynamicMethod dm = new DynamicMethod(binding.NewDynMethodId, typeof(void), args, sourceType); @@ -996,7 +1002,7 @@ namespace go string src = binding.Expression.Trim(); if (! (src.StartsWith("{") || src.EndsWith ("}"))) - throw new Exception (string.Format("GOML:Malformed {0} Event handler: {1}", binding.SourceMember.Name, binding.Expression)); + throw new Exception (string.Format("GOML:Malformed {0} Event handler: {1}", binding.Source.Member.Name, binding.Expression)); src = src.Substring (1, src.Length - 2); string[] srcLines = src.Split (new char[] { ';' }); @@ -1084,8 +1090,8 @@ namespace go #endregion - Delegate del = dm.CreateDelegate(binding.Event.EventHandlerType,this); - MethodInfo addHandler = binding.Event.GetAddMethod (); + Delegate del = dm.CreateDelegate(binding.Source.Event.EventHandlerType,this); + MethodInfo addHandler = binding.Source.Event.GetAddMethod (); addHandler.Invoke(this, new object[] {del}); } @@ -1112,7 +1118,7 @@ namespace go continue; } if (mi.MemberType == MemberTypes.Event) { - this.Bindings.Add (new Binding (mi, attValue)); + this.Bindings.Add (new Binding (new MemberReference(this, mi), attValue)); continue; } if (mi.MemberType == MemberTypes.Property) { @@ -1159,7 +1165,7 @@ namespace go if (!attValue.EndsWith("}")) throw new Exception (string.Format("GOML:Malformed binding: {0}", attValue)); - this.Bindings.Add (new Binding (pi, attValue.Substring (1, attValue.Length - 2))); + this.Bindings.Add (new Binding (new MemberReference(this, pi), attValue.Substring (1, attValue.Length - 2))); continue; } @@ -1276,27 +1282,20 @@ namespace go /// and delete ref of this in Shared interface refs /// public virtual void ClearBinding(){ -// object ds = this.DataSource; -// if (ds != null) { -// Type dataSourceType = ds.GetType (); -// EventInfo evtInfo = dataSourceType.GetEvent ("ValueChanged"); -// if (evtInfo != null) { -// FieldInfo evtFi = CompilerServices.GetEventHandlerField (dataSourceType, "ValueChanged"); -// MulticastDelegate multicastDelegate = evtFi.GetValue (ds) as MulticastDelegate; -// if (multicastDelegate != null) { -// foreach (Delegate d in multicastDelegate.GetInvocationList()) { -// string dn = d.Method.Name; -// if (!dn.StartsWith ("dynHandle_")) -// continue; -// int did = int.Parse (dn.Substring (10)); -// if (this.DynamicMethodIds.Contains (did)) -// evtInfo.RemoveEventHandler (ds, d); -// } -// } -// } -// } -// Interface.Unreference (this); - + foreach (Binding b in Bindings) { + if (string.IsNullOrEmpty (b.DynMethodId)) + continue; + Type dataSourceType = b.Target.Instance.GetType (); + EventInfo evtInfo = dataSourceType.GetEvent ("ValueChanged"); + FieldInfo evtFi = CompilerServices.GetEventHandlerField (dataSourceType, "ValueChanged"); + MulticastDelegate multicastDelegate = evtFi.GetValue (b.Target.Instance) as MulticastDelegate; + if (multicastDelegate != null) { + foreach (Delegate d in multicastDelegate.GetInvocationList()) { + if (d.Method.Name == b.DynMethodId) + evtInfo.RemoveEventHandler (b.Target.Instance, d); + } + } + } } } } diff --git a/src/Interface.cs b/src/Interface.cs index 304e48b6..2ce0266b 100644 --- a/src/Interface.cs +++ b/src/Interface.cs @@ -454,53 +454,6 @@ namespace go return result; } - public static void resolveGOML (object hostClass) - { - foreach (DynAttribute es in GOMLResolver) { -// if (string.IsNullOrEmpty(es.Value)) -// continue; - - Type dstType = es.Source.GetType (); - MemberInfo miTarget = dstType.GetMember (es.MemberName).FirstOrDefault (); - - if (miTarget == null) { - Debug.WriteLine ("'{0}' Member not found in '{1}' type.", es.MemberName, dstType.ToString ()); - continue; - } - - if (miTarget.MemberType == MemberTypes.Event) { - if (es.Value.StartsWith ("{")) { - CompilerServices.CompileEventSource (es); - } else { - MethodInfo mi = hostClass.GetType ().GetMethod (es.Value, BindingFlags.NonPublic | BindingFlags.Public - | BindingFlags.Instance); - - object effectiveHostClass = hostClass; - if (mi == null) { - //TODO: hack to have it work, hostClass and dataSource should be clearly separated - mi = OpenTKGameWindow.currentWindow.GetType ().GetMethod (es.Value, BindingFlags.NonPublic | BindingFlags.Public - | BindingFlags.Instance); - if (mi == null) { - Debug.WriteLine ("Handler Method not found: " + es.Value); - continue; - } - effectiveHostClass = OpenTKGameWindow.currentWindow; - } - - EventInfo ei = es.Source.GetType ().GetEvent (es.MemberName); - MethodInfo addHandler = ei.GetAddMethod (); - Delegate del = Delegate.CreateDelegate (ei.EventHandlerType, effectiveHostClass, mi); - - - addHandler.Invoke (es.Source, new object[] { del }); - - } - } else { - CompilerServices.ResolveBinding (es, hostClass); - } - } - GOMLResolutionStack.Pop (); - } #endregion } -- 2.47.3