Func<EventHandler, get property value from args? - c#

Have tried to solve this for quite a while now, but without luck... My idea was to have some sort of a configuration for different settings, for instance.. controlling how exceptions are handled.
Some of my code :)
public class ErrorEventArgs : EventArgs
{
public bool Handled { get; set; }
...
...
}
A property in my main class like :
EventHandler<ErrorEventArgs> ErrorConfiguration {get; set;}
I then have an OnError where I need to know value of Handled,
internal void OnError(ErrorEventArgs args)
{
Func<EventHandler<ErrorEventArgs>, bool> IsHandled;
IsHandled = ev => ??? // invoke ErrorConfiguration?
if (ErrorConfiguration != null && IsHandled(ErrorConfiguration ))
error(this, args);
}
How can this be solved?
I can do like this, if it's the EventHandler without the Func, but I want to encapsulate the boolean expression. Why cant I chain the lambda... :(
EventHandler<ErrorEventArgs> IsHandled;
IsHandled = (sender, e) => e.ErrorContext.Handled;

I am not completely sure what you want to achieve, exactly. But you can do something like:
IsHandled = ev => { ev(this, args); return args.Handled; };
Even though I am not sure this is more readable, faster, cleaner, or anything like that. I would just go with something like
if (ErrorConfiguration != null) ErrorConfiguration(this, args);
if (!args.Handled) error(this, args);

You really don't need any lambda to call your just need to call your delegate directly:
internal void OnError(ErrorEventArgs args)
{
if (ErrorConfiguration != null)
ErrorConfiguration(this, args);
if (args.Handled)
error(this, args);
}
If you want to the use the same thing in a lambda, you'll have do to this, which will take more lines of code:
internal void OnError(ErrorEventArgs args) {
Func<EventHandler<ErrorEventArgs>, bool> IsHandled;
IsHandled = ev => {
ErrorConfiguration(this, ev);
return ev.Handled;
};
if (ErrorConfiguration != null && IsHandled(ErrorConfiguration ))
error(this, args);
}

Related

Can i pass an variable TSender in a MessagingCenter?

I'm trying to do this with this examples:
public void Method1(object someClassAsTSender, object parameter)
{
//i think parametertype = parameter...
MessagingCenter.Subscribe<someClassAsTSender, parametertype> (this, "messageKey", (message, args) =>
{
Device.BeginInvokeOnMainThread(async () =>
{
//await do;
});
}
);
}
or
public void Method2(object someClassAsTSender, object parameter)
{
//i think parametertype = parameter...
MessagingCenter.Subscribe<someClassAsTSender, parametertype> (this, "messageKey", (message, args) =>
{
//do;
}
);
}
I tryied to use GetType().Name, typeof(), but no have idea how i solve this.
It's just a doubth, because to MVVM i considerate an use of Framework more interestant.
If it is not correct to use MessagingCenter in this way, please explain.
public static void Subscribe<TSender,TArgs> (object subscriber, string message, Action<TSender,TArgs> callback, TSender source = null) where TSender : class;
TArgs is the type of the objects that are used as message arguments for the messageļ¼Œbut you could not use typeof or GetType to set it.you could set it to object like :
public void Method1(object someClassAsTSender, object parameter)
{
//i think parametertype = parameter...
MessagingCenter.Subscribe<someClassAsTSender, object> (this, "messageKey", (message, args) =>
{
//convert the type (e.g string data = args as string)
Device.BeginInvokeOnMainThread(async () =>
{
//await do;
});
}
);
}

Simple event system, can't remove listeners from list

I made a simple event system by following a tutorial, the registration of listeners and firing events works well, but I can't remove any listener from it.
delegate void EventListener(EventInfoBase eventInfo);
Dictionary<System.Type, List<EventListener>> eventListeners;
public void RegisterListener<T>(System.Action<T> listener) where T : EventInfoBase
{
System.Type eventType = typeof(T);
if (eventListeners == null)
{
eventListeners = new Dictionary<System.Type, List<EventListener>>();
}
if (!eventListeners.ContainsKey(eventType) || eventListeners[eventType] == null)
{
eventListeners[eventType] = new List<EventListener>();
}
EventListener wrapper = (ei) => { listener((T)ei); };
eventListeners[eventType].Add(wrapper);
}
public void UnregisterListener<T>(System.Action<T> listener) where T : EventInfoBase
{
System.Type eventType = typeof(T);
if (eventListeners == null)
{
return;
}
if (!eventListeners.ContainsKey(eventType) || eventListeners[eventType] == null)
{
return;
}
EventListener wrapper = (ei) => { listener((T)ei); };
EventListener toRemove = eventListeners[eventType].Find(x => x.Equals(wrapper));
//EventListener toRemove = eventListeners[eventType].Find(x => x.Target == wrapper.Target && x.Method == wrapper.Method);
if (toRemove != null)
{
eventListeners[eventType].Remove(toRemove); // Never gets called
}
}
This is how it's called (it's a singleton):
EventsSystem.Instance.RegisterListener<EventInfoWin>(OnWin);
EventsSystem.Instance.UnregisterListener<EventInfoWin>(OnWin);
So I expected the listener to be removed from appropriate list, but it stays there. The UnregisterListener method does nothing. Any way to fix it quickly without rewriting everything?
Your problem is that in RegisterListener<T> you create an anonymous wrapper method of type EventListener and in UnregisterListener<T> you create another wrapper method. These wrappers will never match.
What you can do is to store the original listener along with the wrapper. That will allow you to match with the original listener, but execute the wrapper (to execute the original listener you would need reflection - hence the wrapper). If you switch from a dictionary to a list of tuples, you can do this in a straightforward way:
delegate void EventListener(object eventInfo);
List<(System.Type Type, Delegate Listener, EventListener Wrapper)> eventListeners;
public void RegisterListener<T>(System.Action<T> listener)
{
System.Type eventType = typeof(T);
if (eventListeners == null)
{
eventListeners = new List<(System.Type, Delegate, EventListener)>();
}
if (!eventListeners.Any(entry => entry.Type.Equals(eventType) &&
entry.Listener.Equals(listener))) {
eventListeners.Add((eventType, listener, ei => listener((T)ei)));
}
}
public void UnregisterListener<T>(System.Action<T> listener)
{
System.Type eventType = typeof(T);
if (eventListeners == null)
{
return;
}
var toRemove = eventListeners.FirstOrDefault(entry => entry.Type.Equals(eventType) &&
entry.Listener.Equals(listener));
eventListeners.Remove(toRemove);
}
You can try it out here.
You cannot use the wrapper delegate as you do. the reason is, that this is creating another "object" on adding, which will not be be recognizable later when you want to remove it.
As Jon Skeet wrote, you can just save the action directly, but as an object. I've tested it, and I did not find a way to have an list with Action of EventInfoBase putting in an Action of EventInfoWin.
So that is what it could look like:
EDIT: I've created a wrapper again, but with the original action as a token to find it again.
delegate void EventListener(EventInfoBase eventInfo);
private class EventWrapper
{
public EventListener Action { get; set; }
public object Token { get; set; }
}
Dictionary<System.Type, List<EventWrapper>> eventListeners = new Dictionary<System.Type, List<EventWrapper>>();
public void RegisterListener<T>(System.Action<T> listener) where T : EventInfoBase
{
System.Type eventType = typeof(T);
if (!eventListeners.ContainsKey(eventType) || eventListeners[eventType] == null)
{
eventListeners[eventType] = new List<EventWrapper>();
}
EventListener action = (ei) => { listener((T)ei); };
var wrapper = new EventWrapper() { Action = action, Token = listener };
eventListeners[eventType].Add(wrapper);
}
public void UnregisterListener<T>(System.Action<T> listener) where T : EventInfoBase
{
System.Type eventType = typeof(T);
if (!eventListeners.ContainsKey(eventType) || eventListeners[eventType] == null)
{
return;
}
var toRemove = eventListeners[eventType].FirstOrDefault(x => x.Token.Equals(listener));
if (toRemove != null)
{
eventListeners[eventType].Remove(toRemove);
}
}

Add and remove event handler via reflection c#

Good day!
My purpose is to implement class which will allow us subscribe and unsubscribe objects to(from) events. Here is the code of my class.
public static class EventSubscriber
{
public static void AddEventHandler(EventInfo eventInfo, object item, Action action)
{
var parameters = GetParameters(eventInfo);
var handler = GetHandler(eventInfo, action, parameters);
eventInfo.AddEventHandler(item, handler);
}
public static void RemoveEventHandler(EventInfo eventInfo,
object item, Action action)
{
var parameters = GetParameters(eventInfo);
var handler = GetHandler(eventInfo, action, parameters);
eventInfo.RemoveEventHandler(item, handler);
}
private static ParameterExpression[] GetParameters(EventInfo eventInfo)
{
return eventInfo.EventHandlerType
.GetMethod("Invoke")
.GetParameters()
.Select(parameter => Expression.Parameter(parameter.ParameterType))
.ToArray();
}
private static Delegate GetHandler(EventInfo eventInfo,
Action action, ParameterExpression[] parameters)
{
return Expression.Lambda(
eventInfo.EventHandlerType,
Expression.Call(Expression.Constant(action),
"Invoke", Type.EmptyTypes), parameters)
.Compile();
}
}
As you can see here are 2 public methods which actually subscribe and unsubscribe objects to(from) event. And here is the sample how I test it
class Program
{
static void Main()
{
Test test = new Test();
test.SubscribeTimer();
while (true)
{
if(test.a == 10)
{
break;
}
}
test.UnsubscribeTimer();
while (true)
{
}
}
}
class Test
{
System.Timers.Timer timer;
public int a = 0;
public Test()
{
timer = new System.Timers.Timer(1000);
timer.Start();
}
public void SubscribeTimer()
{
var eventInfo = typeof(System.Timers.Timer).GetEvent("Elapsed");
EventSubscriber.AddEventHandler(eventInfo, timer, TimerElapsed);
EventSubscriber.RemoveEventHandler(eventInfo, timer, TimerNotElapsed);
}
public void UnsubscribeTimer()
{
var eventInfo = typeof(System.Timers.Timer).GetEvent("Elapsed");
EventSubscriber.AddEventHandler(eventInfo, timer, TimerNotElapsed);
EventSubscriber.RemoveEventHandler(eventInfo, timer, TimerElapsed);
}
public void TimerElapsed()
{
Console.WriteLine("timer elapsed");
a++;
}
public void TimerNotElapsed()
{
Console.WriteLine("timer not elapsed");
a++;
}
}
The expected behaviour of sample is that on the begining we will see the message "timer elapsed" every second, after 10-th second we should see only "timer not elapsed" and we do, but we still see "timer elapsed" too. This means that AddEventHandler method works, but RemoveEventHandler method doesn't.
I would be very happy if you will help me. Thanks in advance.
Had to stitch a bunch of sources together to get what I needed which was a one-stop extension method (that could be easily modified if we switched component vendors) to simply clear all existing Event Handlers on an Event we did not control.
Usage is simple:
thirdPartyControlInstance.ClearEventHandlers(nameof(ThirdPartyControlType.ToolClick));
Here is the code, any suggestions to make it more robust/efficient/cleaner are welcome:
public static class EventExtensions
{
public static void ClearEventHandlers(this object obj, string eventName)
{
if (obj == null)
{
return;
}
var objType = obj.GetType();
var eventInfo = objType.GetEvent(eventName);
if (eventInfo == null)
{
return;
}
var isEventProperty = false;
var type = objType;
FieldInfo eventFieldInfo = null;
while (type != null)
{
/* Find events defined as field */
eventFieldInfo = type.GetField(eventName, BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (eventFieldInfo != null && (eventFieldInfo.FieldType == typeof(MulticastDelegate) || eventFieldInfo.FieldType.IsSubclassOf(typeof(MulticastDelegate))))
{
break;
}
/* Find events defined as property { add; remove; } */
eventFieldInfo = type.GetField("EVENT_" + eventName.ToUpper(), BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic);
if (eventFieldInfo != null)
{
isEventProperty = true;
break;
}
type = type.BaseType;
}
if (eventFieldInfo == null)
{
return;
}
if (isEventProperty)
{
// Default Events Collection Type
RemoveHandler<EventHandlerList>(obj, eventFieldInfo);
// Infragistics Events Collection Type
RemoveHandler<EventHandlerDictionary>(obj, eventFieldInfo);
return;
}
if (!(eventFieldInfo.GetValue(obj) is Delegate eventDelegate))
{
return;
}
// Remove Field based event handlers
foreach (var d in eventDelegate.GetInvocationList())
{
eventInfo.RemoveEventHandler(obj, d);
}
}
private static void RemoveHandler<T>(object obj, FieldInfo eventFieldInfo)
{
var objType = obj.GetType();
var eventPropertyValue = eventFieldInfo.GetValue(obj);
if (eventPropertyValue == null)
{
return;
}
var propertyInfo = objType.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance)
.FirstOrDefault(p => p.Name == "Events" && p.PropertyType == typeof(T));
if (propertyInfo == null)
{
return;
}
var eventList = propertyInfo?.GetValue(obj, null);
switch (eventList) {
case null:
return;
case EventHandlerDictionary typedEventList:
typedEventList.RemoveHandler(eventPropertyValue, typedEventList[eventPropertyValue]);
break;
}
}
}
Hope this helps someone!
I think it's because you are creating a new handler each time: (which doesn't match the previous handler, so can't be removed from the invocation list)
public static void RemoveEventHandler(EventInfo eventInfo,
object item, Action action)
{
var parameters = GetParameters(eventInfo);
var handler = GetHandler(eventInfo, action, parameters); // <--
eventInfo.RemoveEventHandler(item, handler);
}
Why are you wrapping the Action? To lose the parameters? It is not possible to add/remove the eventInfo.RemoveEventHandler(item, action); because of the parameters. If you want to remove a newly generated handler, you should return that handler when you want to remove it.
public static Delegate AddEventHandler(EventInfo eventInfo, object item, Action action)
{
var parameters = GetParameters(eventInfo);
var handler = GetHandler(eventInfo, action, parameters);
eventInfo.AddEventHandler(item, handler);
return handler;
}
public static void RemoveEventHandler(EventInfo eventInfo,
object item, Delegate handler)
{
eventInfo.RemoveEventHandler(item, handler);
}
var handler = EventSubscriber.AddEventHandler(eventInfo, timer, TimerElapsed);
EventSubscriber.RemoveEventHandler(eventInfo, timer, handler);

Background thread lambda callback

At the moment when my background thread is complete it runs a System.Action callback using an anonymous lambda statement. I'm wondering how can I rewrite the code below to have a callback/lambda statement using a Completed function.
ViewModel : BaseViewModel
public override void Initialize(System.Action onInitializeCallback = null)
{.....
BackgroundEntityWorker.RunWorkerCompleted += (sender, args) =>
{
If (onInitializeCallback != null)
{
onInitializeCallback();
}
};
.....
}
I want to change it to something below
BackgroundEntityWorker.RunWorkerCompleted += BackgroundWorker_Completed =>
{
If (onInitializeCallback != null)
{
onInitializeCallback();
}
};
BaseViewModel
public virtual void Reload(int? id = null, Action<T> callback = null)
{
Initialize(() =>
{
Localize();
if (id == null)
{
IndicateLoading(false);
}
else
{
Load(id.Value, () => IndicateLoading(false));
}
});
}
I get an error Argument type 'Lambda expression is not assignable to parameter type System.ComponentModel.RunWorkerCompletedEventHandler
I tried
BackgroundEntityWorker.RunWorkerCompleted += BackgroundWorker_Completed;
but I lose my callback, how do I set it to have BackGroundWorker_Completed and maintain my callback?
BackgroundEntityWorker.RunWorkerCompleted += (sender, args) =>
{
If (onInitializeCallback != null)
{
onInitializeCallback();
}
}
but careful about BackgroundEntityWorker null access
public override void Initialize(System.Action onInitializeCallback = null)
{
If (BackgroundEntityWorker.RunWorkerCompleted != null)
{
BackgroundEntityWorker.RunWorkerCompleted();
}
}
You are redirecting twice the event. It would be easier for us, if you show how your complete event raising

C# Chain Delegates together with "unknown" signatures

I want to do the following:
private static Dictionary<string, Delegate> handlers = new Dictionary<string, Delegate>();
private static void RecievedMessage(object sender, RecievedMessageEventArgs e) {
if(e == null || e.Message == null) return;
if(e.Message is RegisterMethodMessage) {
var registerMethodMsg = (RegisterMethodMessage)e.Message;
if(handlers.ContainsKey(registerMethodMsg.MethodName)) {
handlers[registerMethodMsg.MethodName] += registerMethodMsg.Handler; //Error
} else {
handlers.Add(registerMethodMsg.MethodName, registerMethodMsg.Handler);
}
}
}
A delegate added to the chain with the same key in the dictionary will have the same method signature.
If I were to substitute "Delegate" with a specific one like Action, the above code would work.
So my question is:
Is it possible to do the same without the substitution and without a lot of "hacking"?
Is there any reason you can't do this:
handlers[registerMethodMsg.MethodName] =
Delegate.Combine(
handlers[registerMethodMsg.MethodName],
registerMethodMsg.Handler);

Categories