Skip to content
Snippets Groups Projects
Commit 05465442 authored by Tobias's avatar Tobias
Browse files

optimized reflection without cacheing,

added reflection method for two params,
updated OrderOutput to use reflection service on controlcomponent
parent fcc3b70f
No related branches found
No related tags found
No related merge requests found
......@@ -229,7 +229,7 @@ namespace ControlComponents.Core
}
// In the core ControlComponent targetRole is ignored. This is counterintuitive
// TODO In the core ControlComponent targetRole is ignored. This is counterintuitive
public virtual TReturn ReadProperty<TReturn>(string targetRole, string propertyName)
{
return ControlComponentReflection.ReadProperty<TReturn>(targetRole, propertyName, this);
......@@ -254,6 +254,10 @@ namespace ControlComponents.Core
{
return ControlComponentReflection.CallMethod<TParam, TReturn>(targetRole, methodName, param, this);
}
public virtual TReturn CallMethod<TParam1, TParam2, TReturn>(string targetRole, string methodName, TParam1 param1, TParam2 param2)
{
return ControlComponentReflection.CallMethod<TParam1, TParam2, TReturn>(targetRole, methodName, param1, param2, this);
}
public virtual void Subscribe<T>(string targetRole, string eventName, T eventHandler)
{
......
......@@ -7,85 +7,58 @@ namespace ControlComponents.Core
internal static class ControlComponentReflection
{
static IDictionary<string, object> methodCache = new Dictionary<string, object>();
static IDictionary<string, object> propertyCache = new Dictionary<string, object>();
public static TReturn ReadProperty<TReturn>(string targetRole, string propertyName, IControlComponent instance)
{
var propertyId = propertyName + targetRole + instance.ComponentName;
if (!propertyCache.ContainsKey(propertyId))
// TODO extend this to use all known IControlComponent properties to make the code faster
if(propertyName == nameof(IControlComponent.EXST))
{
// do not use typeof, but GetType to get dynamic type
var propertyInfo = instance.GetType().GetProperty(propertyName);
Func<TReturn> propertyDelegate = PropertyCache.BuildTypedGetter<TReturn>(propertyInfo, instance);
propertyCache.Add(propertyId, propertyDelegate);
return (TReturn)(object)instance.EXST;
}
return (propertyCache[propertyId] as Func<TReturn>).Invoke();
return (TReturn)instance.GetType().GetProperty(propertyName).GetValue(instance);
}
public static void CallMethod(string targetRole, string methodName, IControlComponent instance)
{
var methodId = methodName + targetRole + instance.ComponentName;
if (!methodCache.ContainsKey(methodId))
{
var methodInfo = instance.GetType().GetMethod(methodName);
Action propertyDelegate = PropertyCache.BuildTypedAction(methodInfo, instance);
methodCache.Add(methodId, propertyDelegate);
}
(methodCache[methodId] as Action).Invoke();
instance.GetType().GetMethod(methodName).Invoke(instance, new object[]{});
}
public static TReturn CallMethod<TReturn>(string targetRole, string methodName, IControlComponent instance)
{
var methodId = methodName + targetRole + instance.ComponentName;
if (!methodCache.ContainsKey(methodId))
// TODO extend this to use all known IControlComponent methods to make the code faster
if(methodName == nameof(IControlComponent.IsFree))
{
var methodInfo = instance.GetType().GetMethod(methodName);
Func<TReturn> propertyDelegate = PropertyCache.BuildTypedFunc<TReturn>(methodInfo, instance);
methodCache.Add(methodId, propertyDelegate);
return (TReturn)(object)instance.IsFree();
}
return (methodCache[methodId] as Func<TReturn>).Invoke();
return (TReturn) instance.GetType().GetMethod(methodName).Invoke(instance, new object[]{});
}
public static void CallMethod<TParam>(string targetRole, string methodName, TParam param, IControlComponent instance)
{
var methodId = methodName + targetRole + instance.ComponentName;
if (!methodCache.ContainsKey(methodId))
{
var methodInfo = instance.GetType().GetMethod(methodName);
Action<TParam> propertyDelegate = PropertyCache.BuildTypedAction<TParam>(methodInfo, instance);
methodCache.Add(methodId, propertyDelegate);
}
(methodCache[methodId] as Action<TParam>).Invoke(param);
instance.GetType().GetMethod(methodName).Invoke(instance, new object[]{param});
}
public static TReturn CallMethod<TParam, TReturn>(string targetRole, string methodName, TParam param, IControlComponent instance)
{
var methodId = methodName + targetRole + instance.ComponentName;
if (!methodCache.ContainsKey(methodId))
{
var methodInfo = instance.GetType().GetMethod(methodName);
Func<TParam, TReturn> propertyDelegate = PropertyCache.BuildTypedFunc<TParam, TReturn>(methodInfo, instance);
methodCache.Add(methodId, propertyDelegate);
}
return (TReturn) instance.GetType().GetMethod(methodName).Invoke(instance, new object[]{param});
}
return (methodCache[methodId] as Func<TParam, TReturn>).Invoke(param);
public static TReturn CallMethod<TParam1, TParam2, TReturn>(string targetRole, string methodName, TParam1 param1, TParam2 param2, IControlComponent instance)
{
return (TReturn) instance.GetType().GetMethod(methodName).Invoke(instance, new object[]{param1, param2});
}
public static void Subscribe<T>(string targetRole, string eventName, T eventHandler, IControlComponent instance)
{
EventInfo eventInfo = instance.GetType().GetEvent(eventName);
Action<T> addEventHandler = (Action<T>) eventInfo.GetAddMethod().CreateDelegate(typeof(Action<T>), instance);
Action<T> addEventHandler = (Action<T>)eventInfo.GetAddMethod().CreateDelegate(typeof(Action<T>), instance);
addEventHandler(eventHandler);
}
public static void Unsubscribe<T>(string targetRole, string eventName, T eventHandler, IControlComponent instance)
{
EventInfo eventInfo = instance.GetType().GetEvent(eventName);
Action<T> removeEventHandler = (Action<T>) eventInfo.GetRemoveMethod().CreateDelegate(typeof(Action<T>), instance);
Action<T> removeEventHandler = (Action<T>)eventInfo.GetRemoveMethod().CreateDelegate(typeof(Action<T>), instance);
removeEventHandler(eventHandler);
}
}
......
......@@ -3,7 +3,7 @@ using System.Threading.Tasks;
namespace ControlComponents.Core
{
public interface IControlComponent : IExecutionState, IOccupation
public interface IControlComponent : IExecutionState, IOccupation, IControlComponentReflection
{
string OpModeName { get; }
string WORKST { get; }
......
......@@ -44,6 +44,18 @@ namespace ControlComponents.Core
cc.ExecutionStateChanged -= waiter.EventHandler;
}
public static async Task WaitForIdle(this IControlComponent cc, int delay = 1000)
{
StateWaiter waiter = new StateWaiter();
cc.ExecutionStateChanged += waiter.EventHandler;
if (cc.EXST != ExecutionState.IDLE)
{
await waiter.Idle();
}
cc.ExecutionStateChanged -= waiter.EventHandler;
}
public static async Task ResetAndWaitForIdle(this IControlComponent cc, string occupier)
{
......
......@@ -5,6 +5,7 @@ public interface IControlComponentReflection
void CallMethod<TParam>(string targetRole, string methodName, TParam param);
TReturn CallMethod<TReturn>(string targetRole, string methodName);
TReturn CallMethod<TParam, TReturn>(string targetRole, string methodName, TParam param);
TReturn CallMethod<TParam1, TParam2, TReturn>(string targetRole, string methodName, TParam1 param1, TParam2 param2);
void Subscribe<T>(string targetRole, string eventName, T eventHandler);
void Unsubscribe<T>(string targetRole, string eventName, T eventHandler);
}
......@@ -24,33 +24,33 @@ namespace ControlComponents.Core
public string Role { get; }
public string Id { get; }
public ExecutionState EXST => controlComponent.EXST;
public ExecutionMode EXMODE => controlComponent.EXMODE;
public ExecutionState EXST => controlComponent.ReadProperty<ExecutionState>(Role, nameof(EXST));
public ExecutionMode EXMODE => controlComponent.ReadProperty<ExecutionMode>(Role, nameof(EXMODE));
public string OpModeName => controlComponent.OpModeName;
public ICollection<string> OpModes => controlComponent.OpModes;
public ICollection<string> Roles => controlComponent.Roles;
public string OpModeName => controlComponent.ReadProperty<string>(Role, nameof(OpModeName));
public ICollection<string> OpModes => controlComponent.ReadProperty<ICollection<string>>(Role, nameof(OpModes));
public ICollection<string> Roles => controlComponent.ReadProperty<ICollection<string>>(Role, nameof(Roles));
public event ExecutionStateEventHandler ExecutionStateChanged;
public event OccupationEventHandler OccupierChanged;
public event OperationModeEventHandler OperationModeChanged;
public event ExecutionModeEventHandler ExecutionModeChanged;
public string OCCUPIER => controlComponent.OCCUPIER;
public string OCCUPIER => controlComponent.ReadProperty<string>(Role, nameof(OCCUPIER));
public string ComponentName => controlComponent.ComponentName;
public string ComponentName => controlComponent.ReadProperty<string>(Role, nameof(ComponentName));
public bool IsSet { get; private set; }
public string WORKST => controlComponent.WORKST;
public string WORKST => controlComponent.ReadProperty<string>(Role, nameof(WORKST));
public void Occupy(string sender) => controlComponent.Occupy(sender);
public void Prio(string sender) => controlComponent.Prio(sender);
public void Free(string sender) => controlComponent.Free(sender);
public bool IsOccupied() => controlComponent.IsOccupied();
public bool IsFree() => controlComponent.IsFree();
public void Occupy(string sender) => controlComponent.CallMethod<string>(Role, nameof(Occupy), sender);
public void Prio(string sender) => controlComponent.CallMethod<string>(Role, nameof(Prio), sender);
public void Free(string sender) => controlComponent.CallMethod<string>(Role, nameof(Free), sender);
public bool IsOccupied() => controlComponent.CallMethod<bool>(Role, nameof(IsOccupied));
public bool IsFree() => controlComponent.CallMethod<bool>(Role, nameof(IsFree));
// TODO use IsSet as well
public bool IsUsableBy(string id) => controlComponent.IsUsableBy(id);
public bool IsUsableBy(string id) => controlComponent.CallMethod<string, bool>(Role, nameof(IsUsableBy), id);
private void OnExecutionStateChanged(object sender, ExecutionStateEventArgs e) => ExecutionStateChanged?.Invoke(this.Role, e);
private void OnExecutionModeChanged(object sender, ExecutionModeEventArgs e) => ExecutionModeChanged?.Invoke(this.Role, e);
......@@ -67,63 +67,60 @@ namespace ControlComponents.Core
public OrderOutputTemplate(string role, string id, IControlComponentProvider provider, T cc) : this(role, id, provider)
{
controlComponent = cc;
controlComponent.ExecutionStateChanged += OnExecutionStateChanged;
controlComponent.ExecutionModeChanged += OnExecutionModeChanged;
controlComponent.OccupierChanged += OnOccupierChanged;
controlComponent.OperationModeChanged += OnOperationModeChanged;
SubscribeToEvents();
IsSet = true;
}
public async Task SelectOperationMode(string operationMode)
public Task SelectOperationMode(string operationMode)
{
await controlComponent.SelectOperationMode(operationMode);
return controlComponent.CallMethod<string, Task>(Role, nameof(SelectOperationMode) ,operationMode);
}
public async Task DeselectOperationMode()
public Task DeselectOperationMode()
{
await controlComponent.DeselectOperationMode();
return controlComponent.CallMethod<Task>(Role, nameof(DeselectOperationMode));
}
public void Reset(string sender)
{
controlComponent.Reset(sender);
controlComponent.CallMethod<string>(Role, nameof(Reset), sender);
}
public void Start(string sender)
{
controlComponent.Start(sender);
controlComponent.CallMethod<string>(Role, nameof(Start), sender);
}
public void Stop(string sender)
{
controlComponent.Stop(sender);
controlComponent.CallMethod<string>(Role, nameof(Stop), sender);
}
public void Suspend(string sender)
{
controlComponent.Suspend(sender);
controlComponent.CallMethod<string>(Role, nameof(Suspend), sender);
}
public void Unsuspend(string sender)
{
controlComponent.Unsuspend(sender);
controlComponent.CallMethod<string>(Role, nameof(Unsuspend), sender);
}
public void Hold(string sender)
{
controlComponent.Hold(sender);
controlComponent.CallMethod<string>(Role, nameof(Hold), sender);
}
public void Unhold(string sender)
{
controlComponent.Unhold(sender);
controlComponent.CallMethod<string>(Role, nameof(Unhold), sender);
}
public void Abort(string sender)
{
controlComponent.Abort(sender);
controlComponent.CallMethod<string>(Role, nameof(Abort), sender);
}
public void Clear(string sender)
{
controlComponent.Clear(sender);
controlComponent.CallMethod<string>(Role, nameof(Clear), sender);
}
public override bool Equals(Object obj)
......@@ -140,40 +137,41 @@ namespace ControlComponents.Core
}
}
public override int GetHashCode()
{
return ComponentName.GetHashCode();
}
public bool ChangeComponent(string id)
{
T c = _provider.GetComponent<T>(id);
return this.ChangeComponent(c);
}
private void SubscribeToEvents()
{
controlComponent.Subscribe<ExecutionStateEventHandler>(Role, nameof(ExecutionStateChanged), OnExecutionStateChanged);
controlComponent.Subscribe<ExecutionModeEventHandler>(Role, nameof(ExecutionModeChanged), OnExecutionModeChanged);
controlComponent.Subscribe<OccupationEventHandler>(Role, nameof(OccupierChanged), OnOccupierChanged);
controlComponent.Subscribe<OperationModeEventHandler>(Role, nameof(OperationModeChanged), OnOperationModeChanged);
}
private void UnsubscribeFromEvents()
{
controlComponent.Unsubscribe<ExecutionStateEventHandler>(Role, nameof(ExecutionStateChanged), OnExecutionStateChanged);
controlComponent.Unsubscribe<ExecutionModeEventHandler>(Role, nameof(ExecutionModeChanged), OnExecutionModeChanged);
controlComponent.Unsubscribe<OccupationEventHandler>(Role, nameof(OccupierChanged), OnOccupierChanged);
controlComponent.Unsubscribe<OperationModeEventHandler>(Role, nameof(OperationModeChanged), OnOperationModeChanged);
}
public bool ChangeComponent(T cc)
{
if (!IsSet)
{
controlComponent = cc;
controlComponent.ExecutionStateChanged += OnExecutionStateChanged;
controlComponent.ExecutionModeChanged += OnExecutionModeChanged;
controlComponent.OccupierChanged += OnOccupierChanged;
controlComponent.OperationModeChanged += OnOperationModeChanged;
SubscribeToEvents();
IsSet = true;
return true;
}
else if (controlComponent.EXST == ExecutionState.STOPPED)
else if (EXST == ExecutionState.STOPPED)
{
controlComponent.ExecutionStateChanged -= OnExecutionStateChanged;
controlComponent.ExecutionModeChanged -= OnExecutionModeChanged;
controlComponent.OccupierChanged -= OnOccupierChanged;
controlComponent.OperationModeChanged -= OnOperationModeChanged;
UnsubscribeFromEvents();
controlComponent = cc;
controlComponent.OccupierChanged += OnOccupierChanged;
controlComponent.ExecutionStateChanged += OnExecutionStateChanged;
controlComponent.ExecutionModeChanged += OnExecutionModeChanged;
controlComponent.OperationModeChanged += OnOperationModeChanged;
SubscribeToEvents();
return true;
}
else
......@@ -187,10 +185,7 @@ namespace ControlComponents.Core
if (IsSet)
{
IsSet = false;
controlComponent.ExecutionStateChanged -= OnExecutionStateChanged;
controlComponent.ExecutionModeChanged -= OnExecutionModeChanged;
controlComponent.OccupierChanged -= OnOccupierChanged;
controlComponent.OperationModeChanged -= OnOperationModeChanged;
UnsubscribeFromEvents();
// controlComponent = null;
}
}
......@@ -198,17 +193,57 @@ namespace ControlComponents.Core
// TODO seperate IControlComponent and IOrderOutput for this manner ?
public bool ChangeOutput(string role, string id)
{
return controlComponent.ChangeOutput(role, id);
return controlComponent.CallMethod<string, string, bool>(Role, nameof(ChangeOutput), role, id);
}
public void Auto(string sender) => controlComponent.CallMethod<string>(Role, nameof(Auto), sender);
public void SemiAuto(string sender) => controlComponent.CallMethod<string>(Role, nameof(SemiAuto), sender);
public TReturn ReadProperty<TReturn>(string targetRole, string propertyName)
{
return controlComponent.ReadProperty<TReturn>(targetRole, propertyName);
}
public void CallMethod(string targetRole, string methodName)
{
controlComponent.CallMethod(targetRole, methodName);
}
public void Auto(string sender)
public void CallMethod<TParam>(string targetRole, string methodName, TParam param)
{
controlComponent.Auto(sender);
controlComponent.CallMethod<TParam>(targetRole, methodName, param);
}
public void SemiAuto(string sender)
public TReturn CallMethod<TReturn>(string targetRole, string methodName)
{
return controlComponent.CallMethod<TReturn>(targetRole, methodName);
}
public TReturn CallMethod<TParam, TReturn>(string targetRole, string methodName, TParam param)
{
return controlComponent.CallMethod<TParam, TReturn>(targetRole, methodName, param);
}
public TReturn CallMethod<TParam1, TParam2, TReturn>(string targetRole, string methodName, TParam1 param1, TParam2 param2)
{
return controlComponent.CallMethod<TParam1, TParam2, TReturn>(targetRole, methodName, param1, param2);
}
public void Subscribe<T1>(string targetRole, string eventName, T1 eventHandler)
{
// IMPORTANT: subscribe to OrderOutput events and not controlcomponent, because controlcomponent might be changed
ControlComponentReflection.Subscribe<T1>(targetRole, eventName, eventHandler, this);
}
public void Unsubscribe<T1>(string targetRole, string eventName, T1 eventHandler)
{
ControlComponentReflection.Unsubscribe<T1>(targetRole, eventName, eventHandler, this);
}
public override int GetHashCode()
{
controlComponent.SemiAuto(sender);
return (Role + Id).GetHashCode();
}
}
}
......@@ -23,6 +23,12 @@ namespace ControlComponents.Core
return (Func<TParam, TReturn>)reflGet;
}
public static Func<TParam1, TParam2, TReturn> BuildTypedFunc<TParam1, TParam2, TReturn>(MethodInfo methodInfo, object instance)
{
var reflGet = Delegate.CreateDelegate(typeof(Func<TParam1, TParam2, TReturn>), instance, methodInfo);
return (Func<TParam1, TParam2, TReturn>)reflGet;
}
public static Action<TParam> BuildTypedAction<TParam>(MethodInfo methodInfo, object instance)
{
var reflGet = Delegate.CreateDelegate(typeof(Action<TParam>), instance, methodInfo);
......
......@@ -83,13 +83,12 @@ namespace ControlComponents.Core.Tests
sw.Start();
// ExecutionState test;
// ExecutionState testE;
// bool test;
for (int i = 0; i < 10000000; i++)
{
// test = sut.EXST; // 0.06 sec
// test = sut.ReadProperty<ExecutionState>("", nameof(sut.EXST)); // 0.51 sec
// test = sut.ReadPropertyyy<ExecutionState>("", nameof(sut.EXST)); // 1.88 sec
// testE = sut.EXST; // 0.06 sec
// testE = sut.ReadProperty<ExecutionState>("", nameof(sut.EXST)); // 0.51 sec
//test = sut.CallMethod<bool>("", nameof(sut.IsFree)); // 0.46 sec (without cache was 4.87 sec)
// test = sut.IsFree(); // 0.09 sec
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment