Changeset 4788


Ignore:
Timestamp:
11/13/10 10:26:04 (8 years ago)
Author:
abeham
Message:

#1258

  • Changed event handler cache to be static and keeping the DynamicMethod
  • Added case when source property was null
  • Added regions to clarify code a little
File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/ParameterBinding/HeuristicLab.Core/3.3/ItemBinding.cs

    r4787 r4788  
    2323    private bool bound;
    2424
    25     private Dictionary<Type, Delegate> eventHandlerCache = new Dictionary<Type, Delegate>();
     25    private static object evhCacheLock = new object();
     26    private static Dictionary<Type, DynamicMethod> eventHandlerCache = new Dictionary<Type, DynamicMethod>();
    2627
    2728    [StorableConstructor]
     
    9495      string[] sourceProperties = sourcePath.Split('.');
    9596      object cSource = source;
    96       PropertyInfo bindingProperty = null;
     97      #region Navigate to source property
    9798      bool reregister = false;
    9899      for (int i = 0; i < sourceProperties.Length; i++) {
     
    101102        if (reregister) TryHookToChangedEvent(cSource, property + "Changed");
    102103        if (cSource == sender) reregister = true;
    103         bindingProperty = cSource.GetType().GetProperty(property, Flags);
    104         object next = bindingProperty.GetGetMethod(true).Invoke(cSource, null);
     104        object next = cSource.GetType().GetProperty(property, Flags).GetGetMethod(true).Invoke(cSource, null);
    105105        cSource = next;
    106106      }
     107      #endregion
    107108
    108109      string[] targetProperties = targetPath.Split('.');
    109110      object cTarget = target;
     111      MethodInfo targetSetter = null;
     112      #region Navigate to target property
    110113      for (int i = 0; i < targetProperties.Length - 1; i++) {
    111114        cTarget = cTarget.GetType().GetProperty(targetProperties[i], Flags).GetGetMethod(true).Invoke(cTarget, null);
    112115        if (cTarget == null) return;
    113116      }
    114       MethodInfo setter = cTarget.GetType().GetProperty(targetProperties.Last(), Flags).GetSetMethod(true);
    115       if (cSource.GetType().IsValueType)
    116         setter.Invoke(cTarget, new object[] { cSource });
     117      targetSetter = cTarget.GetType().GetProperty(targetProperties.Last(), Flags).GetSetMethod(true);
     118      if (targetSetter == null) return;
     119      #endregion
     120
     121      if (cSource == null && !targetSetter.GetParameters().First().ParameterType.IsValueType
     122        || cSource != null && cSource.GetType().IsValueType)
     123        targetSetter.Invoke(cTarget, new object[] { cSource });
    117124      else if (cSource is ICloneable)
    118         setter.Invoke(cTarget, new object[] { ((ICloneable)cSource).Clone() });
     125        targetSetter.Invoke(cTarget, new object[] { ((ICloneable)cSource).Clone() });
    119126      else throw new InvalidOperationException("Can only bind to targets which are either a ValueType or an ICloneable.");
    120127    }
     
    126133        if (!eventHandlerCache.ContainsKey(methodParams[1]))
    127134          CreateAndAddDynamicEventHandler(eInfo, methodParams);
    128         eInfo.AddEventHandler(obj, eventHandlerCache[methodParams[1]]);
     135        eInfo.AddEventHandler(obj, eventHandlerCache[methodParams[1]].CreateDelegate(eInfo.EventHandlerType, this));
    129136      }
    130137      return eInfo != null;
     
    136143        Type[] methodParams = eInfo.EventHandlerType.GetMethod("Invoke").GetParameters().Select(x => x.ParameterType).ToArray();
    137144        if (eventHandlerCache.ContainsKey(methodParams[1]))
    138           eInfo.RemoveEventHandler(obj, eventHandlerCache[methodParams[1]]);
     145          eInfo.RemoveEventHandler(obj, eventHandlerCache[methodParams[1]].CreateDelegate(eInfo.EventHandlerType, this));
    139146      }
    140147      return eInfo != null;
     
    142149
    143150    private void CreateAndAddDynamicEventHandler(EventInfo eInfo, Type[] methodParams) {
    144       Type[] instanceMethodParams = new Type[] { GetType() }.Concat(methodParams).ToArray();
    145       DynamicMethod dynamicEventHandler = new DynamicMethod("sourceChanged", null, instanceMethodParams, GetType());
    146       MethodInfo executeBindingMethodInfo = GetType().GetMethod("ExecuteBinding", Flags);
    147       ILGenerator iLG = dynamicEventHandler.GetILGenerator();
    148       iLG.Emit(OpCodes.Ldarg_0); // load 'this' pointer
    149       iLG.Emit(OpCodes.Ldarg_1); // load sender parameter
    150       iLG.Emit(OpCodes.Call, executeBindingMethodInfo); // call method to execute the binding
    151       iLG.Emit(OpCodes.Ret);
    152       eventHandlerCache.Add(methodParams[1], dynamicEventHandler.CreateDelegate(eInfo.EventHandlerType, this));
     151      lock (evhCacheLock) {
     152        if (!eventHandlerCache.ContainsKey(methodParams[1])) {
     153          Type[] instanceMethodParams = new Type[] { GetType() }.Concat(methodParams).ToArray();
     154          DynamicMethod dynamicEventHandler = new DynamicMethod("sourceChanged", null, instanceMethodParams, GetType());
     155          MethodInfo executeBindingMethodInfo = GetType().GetMethod("ExecuteBinding", Flags);
     156          ILGenerator iLG = dynamicEventHandler.GetILGenerator();
     157          iLG.Emit(OpCodes.Ldarg_0); // load 'this' pointer
     158          iLG.Emit(OpCodes.Ldarg_1); // load sender parameter
     159          iLG.Emit(OpCodes.Call, executeBindingMethodInfo); // call method to execute the binding
     160          iLG.Emit(OpCodes.Ret);
     161          eventHandlerCache.Add(methodParams[1], dynamicEventHandler);
     162        }
     163      }
    153164    }
    154165  }
Note: See TracChangeset for help on using the changeset viewer.