Remove duplicate delegate from event - c#

I would like to remoe duplicate delegates from an event. So I have written the following code. It works fine. My application is a time critcal application. Is there any other optimized mechansim to achieve the same. Please help me
public void FireEvent()
{
Dictionary<Delegate, Delegate> dic = new Dictionary<Delegate, Delegate>();
Delegate[] m = this.Paused.GetInvocationList();
foreach (Delegate d in m)
{
Delegate dout;
if (dic.TryGetValue(d, out dout))
{
continue;
}
else
{
dic.Add(d, d);
}
d.DynamicInvoke(new object[2] { this, null });
}
}

Problem with original approach
If this is really a time critical application, I would strongly advise changing your code.
You construct and populate a new Dictionary<Delegate, Delegate> on every method call. This is quite wasteful.
You use DynamicInvoke, which has slower performance than regular invocation to begin with.
You construct a new object[] to pass as a parameter to your DynamicInvoke call, again on every FireEvent call.
This is a bit of a corruption of the established mechanism for event handling.
Suggestion for improved approach
Here's a much better solution, in my opinion: instead of having this FireEvent method which bends over backwards to ignore duplicate delegates that have been added, why not just prevent delegates from being attached to the event multiple times in the first place?
private HashSet<EventHandler> _pausedHandlers = new HashSet<EventHandler>();
public event EventHandler Paused
{
add // will not add duplicates
{ _pausedHandlers.Add(value); }
remove
{ _pausedHandlers.Remove(value); }
}
Then you can simply raise the event in the much more conventional, time-tested way, confident that no delegates have been attached to the event more than once.
protected void OnPaused()
{
foreach (EventHandler handler in _pausedHandlers)
{
try
{
handler(this, EventArgs.Empty);
}
catch
{
// up to you what to do here
}
}
}
Note on the concept of "duplicate delegates"
The comments to this answer have shed some light on the issue of delegate equality that I felt it would be beneficial to include in this answer. If you're interested, take a look at the following code example I wrote in an attempt to make this topic a little bit easier to understand.
class Program
{
static void Main(string[] args)
{
// Even though the code for FirstHandler and SecondHandler is the same,
// they will not (nor should they) be considered equal for the purpose
// of detecting duplicates.
EventHandler handler1 = FirstHandler;
EventHandler handler2 = SecondHandler;
// Since handler2 and handler3 point to the same method, on the other
// hand, they will (and ought to) be treated as equal.
EventHandler handler3 = SecondHandler;
// So this prints 'False'...
Console.WriteLine(handler1.Equals(handler2));
// ...and this prints 'True'.
Console.WriteLine(handler2.Equals(handler3));
// Now take a look at the code for SetAnonymousHandler below. The
// method accepts an EventHandler by reference and compares it for
// equality to a delegate pointing to an anoymous lambda method. If the
// two are equal, it sets the EventHandler to this new delegate and
// returns true; otherwise it returns false.
// This prints 'True', as handler1 is not equal to the delegate
// declared within the SetAnonymousHandler method.
Console.WriteLine(SetAnonymousHandler(ref handler1));
// HOWEVER, now it prints 'False' for a simple reason: the delegate
// declared in SetAnonymousHandler points to an actual method. The fact
// that it is an anonymous method simply means that the compiler
// automatically generates a "proper" method for it in IL (to see what
// I mean, read the comment at the bottom of this class). So now,
// as with handler2 and handler3 above, handler1 and the delegate
// declared in SetAnonymousHandler point to the same method and are
// therefore equal; the method returns false.
Console.WriteLine(SetAnonymousHandler(ref handler1));
Console.ReadLine();
}
static void FirstHandler(object sender, EventArgs e)
{
Console.WriteLine("Testing");
}
static void SecondHandler(object sender, EventArgs e)
{
Console.WriteLine("Testing");
}
static bool SetAnonymousHandler(ref EventHandler handler)
{
EventHandler anonymous = (sender, e) => Console.WriteLine("Testing");
if (!handler.Equals(anonymous))
{
handler = anonymous;
return true;
}
else
{
return false;
}
}
// Note: When the above method is compiled, the C# compiler generates code
// that would look something like this if translated back from IL to C#
// (not exactly, but the point is just to illustrate that an anoymous
// method, after compilation, is really just like a "proper"
// -- i.e., non-anonymous -- method).
//static bool SetAnonymousHandler(ref EventHandler handler)
//{
// EventHandler anonymous = SetAnonymousHandler_Anonymous;
// if (handler.Equals(anonymous))
// {
// handler = anonymous;
// return true;
// }
// else
// {
// return false;
// }
//}
//static void SetAnonymousHandler_Anonymous(object sender, EventArgs e)
//{
// Console.WriteLine("Testing");
//}
}

Related

c# Event Creation: Raise vs invoke

Before C#6, i was using this routine to deal with generating events in a multi threaded program: (i found it somewhere, but can't remember where):
public static object Raise(this MulticastDelegate multicastDelegate, object sender, EventArgs e)
{
object retVal = null;
MulticastDelegate threadSafeMulticastDelegate = multicastDelegate;
if (threadSafeMulticastDelegate != null)
{
foreach (Delegate d in threadSafeMulticastDelegate.GetInvocationList())
{
var synchronizeInvoke = d.Target as ISynchronizeInvoke;
if ((synchronizeInvoke != null) && synchronizeInvoke.InvokeRequired)
retVal = synchronizeInvoke.EndInvoke(synchronizeInvoke.BeginInvoke(d, new[] { sender, e }));
else
retVal = d.DynamicInvoke(sender, e);
}
}
return retVal;
}
so all i had to do was Eventname.Raise(...,....)
now with C#6, i know the new was it using something like:
Eventname?.Invoke(...);
what i am wondering is, should i change all my event creations to Invoke as it works different to the Raise(), or is it the same thing ?
You should never have been using that method in the first place. It's way too complicated. Instead, something like this would have been better:
public static void Raise(this Delegate handler, object sender, EventArgs e)
{
if (handler != null)
{
handler.DynamicInvoke(sender, e);
}
}
As for whether you should change your event-raising code, I'd say no. Not unless you've got a lot of time to kill and like going through your entire code base replacing perfectly good code.
What you should do is fix your current Raise() method. And feel free for any new code to write it the new C# 6 way, i.e. MyEvent?.DynamicInvoke(this, EventArgs.Empty) (which effectively amounts to the exact same thing as MyEvent.Raise(this, EventArgs.Empty) using the above, except without the extra method call).

Temporarily stop form events from either being raised or being handled?

I have a ton on controls on a form, and there is a specific time when I want to stop all of my events from being handled for the time being. Usually I just do something like this if I don't want certain events handled:
private bool myOpRunning = false;
private void OpFunction()
{
myOpRunning = true;
// do stuff
myOpRunning = false;
}
private void someHandler(object sender, EventArgs e)
{
if (myOpRunning) return;
// otherwise, do things
}
But I have A LOT of handlers I need to update. Just curious if .NET has a quicker way than having to update each handler method.
You will have to create your own mechanism to do this. It's not too bad though. Consider adding another layer of abstraction. For example, a simple class called FilteredEventHandler that checks the state of myOpRunning and either calls the real event handler, or suppresses the event. The class would look something like this:
public sealed class FilteredEventHandler
{
private readonly Func<bool> supressEvent;
private readonly EventHandler realEvent;
public FilteredEventHandler(Func<bool> supressEvent, EventHandler eventToRaise)
{
this.supressEvent = supressEvent;
this.realEvent = eventToRaise;
}
//Checks the "supress" flag and either call the real event handler, or skip it
public void FakeEventHandler(object sender, EventArgs e)
{
if (!this.supressEvent())
{
this.realEvent(sender, e);
}
}
}
Then when you hook up the event, do this:
this.Control.WhateverEvent += new FilteredEventHandler(() => myOpRunning, RealEventHandler).FakeEventHandler;
When WhateverEvent gets raised, it will call the FilteredEventHandler.FakeEventHandler method. That method will check the flag and either call, or not call the real event handler. This is pretty much logically the same as what you're already doing, but the code that checks the myOpRunning flag is in only one place instead of sprinkled all over your code.
Edit to answer question in the comments:
Now, this example is a bit incomplete. It's a little difficult to unsubscribe from the event completely because you lose the reference to the FilteredEventHandler that's hooked up. For example, you can't do:
this.Control.WhateverEvent += new FilteredEventHandler(() => myOpRunning, RealEventHandler).FakeEventHandler;
//Some other stuff. . .
this.Control.WhateverEvent -= new FilteredEventHandler(() => myOpRunning, RealEventHandler).FakeEventHandler; //Not gonna work!
because you're hooking up one delegate and unhooking a completely different one! Granted, both delegates are the FakeEventHandler method, but that's an instance method and they belong to two completely different FilteredEventHandler objects.
Somehow, you need to get a reference to the first FilteredEventHandler that you constructed in order to unhook. Something like this would work, but it involves keeping track of a bunch of FilteredEventHandler objects which is probably no better than the original problem you're trying to solve:
FilteredEventHandler filter1 = new FilteredEventHandler(() => myOpRunning, RealEventHandler);
this.Control.WhateverEvent += filter1.FakeEventHandler;
//Code that does other stuff. . .
this.Control.WhateverEvent -= filter1.FakeEventHandler;
What I would do, in this case, is to have the FilteredEventHandler.FakeEventHandler method pass its 'this' reference to the RealEventHandler. This involves changing the signature of the RealEventHandler to either take another parameter:
public void RealEventHandler(object sender, EventArgs e, FilteredEventHandler filter);
or changing it to take an EventArgs subclass that you create that holds a reference to the FilteredEventHandler. This is the better way to do it
public void RealEventHandler(object sender, FilteredEventArgs e);
//Also change the signature of the FilteredEventHandler constructor:
public FilteredEventHandler(Func<bool> supressEvent, EventHandler<FilteredEventArgs> eventToRaise)
{
//. . .
}
//Finally, change the FakeEventHandler method to call the real event and pass a reference to itself
this.realEvent(sender, new FilteredEventArgs(e, this)); //Pass the original event args + a reference to this specific FilteredEventHandler
Now the RealEventHandler that gets called can unsubscribe itself because it has a reference to the correct FilteredEventHandler object that got passed in to its parameters.
My final advice, though is to not do any of this! Neolisk nailed it in the comments. Doing something complicated like this is a sign that there's a problem with the design. It will be difficult for anybody who needs to maintain this code in the future (even you, suprisingly!) to figure out the non-standard plumbing involved.
Usually when you're subscribing to events, you do it once and forget it - especially in a GUI program.
You can do it with reflection ...
public static void UnregisterAllEvents(object objectWithEvents)
{
Type theType = objectWithEvents.GetType();
//Even though the events are public, the FieldInfo associated with them is private
foreach (System.Reflection.FieldInfo field in theType.GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance))
{
//eventInfo will be null if this is a normal field and not an event.
System.Reflection.EventInfo eventInfo = theType.GetEvent(field.Name);
if (eventInfo != null)
{
MulticastDelegate multicastDelegate = field.GetValue(objectWithEvents) as MulticastDelegate;
if (multicastDelegate != null)
{
foreach (Delegate _delegate in multicastDelegate.GetInvocationList())
{
eventInfo.RemoveEventHandler(objectWithEvents, _delegate);
}
}
}
}
}
You could just disable the container where all these controls are put in. For example, if you put them in a GroupBox or Panel simply use: groupbox.Enabled = false; or panel.Enabled = false;. You could also disable the form From1.Enabled = false; and show a wait cursor. You can still copy and paste these controls in a container other than the form.

How to manually invoke an event?

I have the following line in C#:
_timer.ElapsedTick += _somefunction1;
_timer.ElapsedTick += _somefunction2;
_timer.ElapsedTick += _somefunction3;
How to invoke all methods subscribed to _timer.ElapsedTick without specifying the _somefunction ? Somewhere along this pseudo-line
invoke(_timer.ElapsedTick);
You can't invoke an event which is owned by another type. An event can only be invoked from the inside of the class which declares it.
Can it be done using conventional C#? No (as previously stated). But using reflection it is possible. Here is some tested code based on the answer to this MSDN forum thread:
class InvokeFromMe
{
public event EventHandler RaiseMe;
}
class Program
{
static void Main(string[] args)
{
var fromMe = new InvokeFromMe();
fromMe.RaiseMe += fromMe_RaiseMe;
fromMe.RaiseMe += fromMe_RaiseMe1;
fromMe.RaiseMe += fromMe_RaiseMe2;
FireEvent(fromMe, "RaiseMe", null, EventArgs.Empty);
}
static void fromMe_RaiseMe(object sender, EventArgs e)
{
Console.WriteLine("Event Handler 0 Raised");
}
static void fromMe_RaiseMe1(object sender, EventArgs e)
{
Console.WriteLine("Event Handler 1 Raised");
}
static void fromMe_RaiseMe2(object sender, EventArgs e)
{
Console.WriteLine("Event Handler 2 Raised");
}
public static void FireEvent(object onMe, string invokeMe, params object[] eventParams)
{
MulticastDelegate eventDelagate =
(MulticastDelegate)onMe.GetType().GetField(invokeMe,
System.Reflection.BindingFlags.Instance |
System.Reflection.BindingFlags.NonPublic).GetValue(onMe);
Delegate[] delegates = eventDelagate.GetInvocationList();
foreach (Delegate dlg in delegates)
{
dlg.Method.Invoke(dlg.Target, eventParams);
}
}
}
UPDATE
I'm not familiar with the System.Timer.Timer class, so I'm not sure what is different from my provided example. You could perhaps try something like:
public static void FirePublicEvent(object onMe, string invokeMe, params object[] eventParams)
{
MulticastDelegate eventDelagate =
(MulticastDelegate)onMe.GetType().GetField(invokeMe,
System.Reflection.BindingFlags.Instance |
System.Reflection.BindingFlags.Public).GetValue(onMe);
Delegate[] delegates = eventDelagate.GetInvocationList();
foreach (Delegate dlg in delegates)
{
dlg.Method.Invoke(dlg.Target, eventParams);
}
}
well i end up here about searching how to simply start event, which is not having any custom args or anything. I know OP question is different! but i had like to share, i hope it helps someone.
Unsimplify version:
var Handler = EventNameHere;
if (Handler != null)
{
Handler(this, EventArgs.Empty);
}
Simplify version:
EventNameHere?.Invoke(this, EventArgs.Empty);
You could create a function that runs them all:
public void RunAllFuncs()
{
_somefunction1();
_somefunction2();
_somefunction3();
}
This is a work around, you can't loop through the Elapsed event. But to invoke them all, let the timer do the work. This code for System.Timer, not sure which timer you are using.
Presuming the timer is already enabled:
int interval = timer.Interval;
ElapsedEventHandler handler = null;
handler = (s,e) =>
{
timer.Interval = interval; // put interval back to original value
timer.Elapsed -= handler;
};
timer.Elapsed += handler;
timer.Interval = 1; // 1 millisecond, pretty much going to fire right now (as soon as you let it)
Something like that will fire the events, but your original interval will be restarted. You may have to do some math in there if you want to keep the original tick pattern.
I think you probably need to use InvokeMember:
public void GetMethod(string methodName){
var args = new Object[] { [INSERT ARGS IF NECESSARY--SET TO NULL OTHERWISE] };
try
{
var t = new [INSERT NAME OF CLASS THAT CONTAINS YOUR METHOD]();
Type typeInfo = t.GetType();
var result = typeInfo.InvokeMember(methodName, BindingFlags.InvokeMethod, null, t, args);
return result;
}
catch (Exception ex)
{
return ex;
}
}
Then call it like this:
_timer.ElapsedTick += GetMethod("[INSERT METHOD NAME AS STRING]");
Be sure to include this:
using System.Reflection;
Good Luck!
Based on M.Babcock's answer above, with some slight reflection method updates.
Replaced GetField with GetTypeInfo and GetDeclaredField, and dlg.Method with dlg.GetMethodInfo.
using System.Reflection;
...
public static void FireEvent(this object onMe, string invokeMe, params object[] eventParams)
{
TypeInfo typeInfo = onMe.GetType().GetTypeInfo();
FieldInfo fieldInfo = typeInfo.GetDeclaredField(invokeMe);
MulticastDelegate eventDelagate = (MulticastDelegate)fieldInfo.GetValue(onMe);
Delegate[] delegates = eventDelagate.GetInvocationList();
foreach (Delegate dlg in delegates)
{
dlg.GetMethodInfo().Invoke(dlg.Target, eventParams);
}
}
With .NET 6 (may work with other versions, too), the following generic method may be helpful. Like in other answers it uses reflection to invoke the EventHandler:
private void InvokeEvent<T, TEvent>(T target, string eventName, TEvent #event)
{
// some reflection magic to fire an event from outside the target class:
if(target == null)
{
throw new ArgumentNullException(nameof(target));
}
Type targetType = target.GetType();
FieldInfo? fi = targetType.GetField(eventName, BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance);
if(fi != null)
{
EventHandler<TEvent>? eventHandler = fi.GetValue(target) as EventHandler<TEvent>;
if(eventHandler != null)
{
eventHandler.Invoke(this, #event);
}
}
}
It can then be invoked like this:
const string eventName = nameof(Algorithm.Received);
DomainEvent #event = new DomainEvent(payload);
InvokeEvent(targetObject, eventName, #event);
Notes:
The above code also works if multiple methods were added with += to the event handler.
If you want use this code in product you may want to consider more error handling such as parameter checking or throwing an exception if a specific event handler wasn't found.
With each major version of .NET the code using reflection may need to be changed. As .NET 6 is cross-platform running on Windows, Linux, MacOS, etc. I suspect the likelihood of changes breaking the above code is reduced, although not zero.
We are using this code in our automated test suite. In case the code using reflection does in fact change, we only need to change this one method.
Building on the answers before me, the following worked for me:
EventNameHere(null, EventArgs.Empty);
Depending on the signature of the ElapsedTick event, you can fire the event by calling it like a method from inside the class in which it is declared. For example:
ElapsedTick(this, new EventArgs());
You can only call events from inside the class that declares it. If you wrote the timer class, you would invoke it like this:
this.ElapsedTick(this, eventArgs);
Outside the timer class you may do as follows to get similar behavior:
delegate void delegateSample(object sender, EventArgs e);
delegateSample d;
d += new delegateSample(_somefunction1);
d += new delegateSample(_somefunction2);
d(this, EventArgs.Empty);
delegateSample should actually be the type of the ElapsedTick event, instead of declaring another delegate type. I just didn't know the name of that delegate. Just make sure you add each function the ElapsedTick event and the delegate variable you declare then you can call them all from the delegate outside the Timer class.

Code improvement: Better alternatives to this pattern?

In a similar question:
What is this pattern called? Soft Lock?
I was asking about the name of the pattern for the code listing below.
public class MyClass
{
public event EventHandler MyEvent;
private bool IsHandlingEvent = false;
public MyClass()
{
MyEvent += new EventHandler(MyClass_MyEvent);
}
void MyClass_MyEvent(object sender, EventArgs e)
{
if (IsHandlingEvent) { return; }
IsHandlingEvent = true;
{
// Code goes here that handles the event, possibly invoking 'MyEvent' again.
// IsHandlingEvent flag is used to avoid redundant processing. What is this
// technique, or pattern called.
// ...
}
IsHandlingEvent = false;
}
}
It seems that most of the conversation was centered around why we should an should not do this, so I think that this question provides a better forum to tackle the problem and address all of the issues. What is the better / proper way to handle this?
There are series of problems with that pattern. If you want to invoke the handler only once, you would do something like this:
protected static object _lockObj = new object();
protected static bool _isHandled = false;
void MyClass_MyEvent(object sender, EventArgs e)
{
if(_isHandled)
return;
lock(_lockObj)
{
if(_isHandled)
return;
_isHandled = true;
MyOtherPossiblyRecursiveMethod(); // Actually does all your work
_isHandled = false;
}
}
void MyOtherPossiblyRecursiveMethod()
{
}
This way, only one thread should be able to access the actual work method.
I will use something like:
using( var sl = new SoftLock() )
{
sl.Execute(()=>{....});
}
the execute will raise the internal boolean to prevent re-entering. In the dispose that flag would be resetted. Execute will call the lambda just if the flag is false. This is to ensure flag go to false even if exception happens ( causing handler never executed ) and maybe is a little better to see. Of course this is not thread safe, as the original code, but this because we are talking about preventing double execution from the same thread.
The original code is a sufficient (and very lightweight) way to prevent recursion in a single-threaded app. So if during your event handling function you could get into code that might be firing the event again you will not enter infinite recursion.
But the code is not sufficient to prevent access from multiple threads, due to the potential for race conditions. If you need to ensure only one thread gets to run this event, then you should use a stronger locking mechanism, like a Mutex or Semaphore.
The following works in single- and multi-threaded scenarios and is exception-safe... also if need be it can be modified to allow for a certain level of reentrancy (for example 3 levels)...
public class MyClass
{
public event EventHandler MyEvent;
private int IsHandlingEvent = 0;
public MyClass()
{
MyEvent += new EventHandler(MyClass_MyEvent);
}
void MyClass_MyEvent(object sender, EventArgs e)
{
// this allows for nesting if needed by comparing for example < 3 or similar
if (Interlocked.Increment (ref IsHandlingEvent) == 1 )
{
try {
}
finally {};
}
Interlocked.Decrement (ref IsHandlingEvent);
}
}

c# event handler being added twice

This is a fictional example but I was wandering what happens if the InitialiseTimer function gets called twice. Does the timer elapsed function get triggered twice. Will this change if the functions are made static?
private static void InitialiseTimer()
{
TheTimer = new System.Timers.Timer();
TheTimer.Interval = 400;
TheTimer.Elapsed += new ElapsedEventHandler(TheTimer_Elapsed);
TheTimer.AutoReset = false;
}
public void TheTimer_Elapsed(object sender, ElapsedEventArgs e)
{
//Do stuff in here
}
I was going to use below to prevent this
Has an event handler already been added?
Thanks,
Richard
If you register the event handler twice, it will be invoked twice every time the event is raised.
This won't change if you make TheTimer_Elapsed static, because you'll still hold two references to this static method.
In most cases there's no need to write compicated things like what Blair Conrad posted in the question you linked to. Just don't forget to use -= every time you have += and you'll be safe.
I think the following demonstrates the scenario and does indeed fire twice, also propose a simple change (commented code) to the Init method that should fix the behavior. (Not thread safe btw, additional locks would be required)
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
var counter = 0;
var ts = new ThreadStart(() =>
{
Foo.Fired += (o, e) =>
{
counter++;
};
Foo.InitialiseTimer();
Foo.InitialiseTimer();
});
var t = new Thread(ts);
t.Start();
Thread.Sleep(30);
Assert.AreEqual(1, counter);
}
}
public class Foo
{
private static System.Timers.Timer TheTimer = null;
public static event EventHandler Fired;
public static void InitialiseTimer()
{
//if (TheTimer != null)
//{
// TheTimer.Stop();
// TheTimer = null;
//}
TheTimer = new System.Timers.Timer();
TheTimer.Interval = 10;
TheTimer.Elapsed += new ElapsedEventHandler(TheTimer_Elapsed);
TheTimer.AutoReset = false;
TheTimer.Start();
}
public static void TheTimer_Elapsed(object sender, ElapsedEventArgs e)
{
//Do stuff in here
if (Fired != null)
{
Fired(null, null);
}
}
}
if you call the method InitialiseTimer twice you will create two Timers each of them will have only one event handler attached but they might elapse both. It's not really about having the method static or not, it's more about the method itself, you could check if TheTimer is null and do the rest only if it's null so you assign it only once.
If event is registered twice you will have two executions.
You can check if event is null, and the problem will be solved.
Static or not, you are recreating the Timer. So you can invoke the InitialiseTimer many, many times without adding more than a single handler. You will end up with many timers though...

Categories