If I am assigning an event handler at runtime and it is in a spot that can be called multiple times, what is the recommended practice to prevent multiple assignments of the same handler to the same event.
object.Event += MyFunction
Adding this in a spot that will be called more than once will execute the handler 'n' times (of course).
I have resorted to removing any previous handler before trying to add via
object.Event -= MyFunction;
object.Event += MyFunction;
This works but seems off somehow. Any suggestions on proper handling ;) of this scenario.
Baget is right about using an explicitly implemented event (although there's a mixture there of explicit interface implementation and the full event syntax). You can probably get away with this:
private EventHandler foo;
public event EventHandler Foo
{
add
{
// First try to remove the handler, then re-add it
foo -= value;
foo += value;
}
remove
{
foo -= value;
}
}
That may have some odd edge cases if you ever add or remove multicast delegates, but that's unlikely. It also needs careful documentation as it's not the way that events normally work.
I tend to add an event handler in a path that's executed once, for example in a constructor.
You can implement your own storage of the delgates, and check for uniqueness when adding them to the event. See EventOwner2 class below for an example. I don't know how this is doing performance wise, but than again, that is not always an issue.
using System;
using System.Collections.Generic;
namespace EventExperiment
{
class Program
{
static void Main(string[] args)
{
IEventOwner e=new EventOwner2();
Subscriber s=new Subscriber(e);
e.RaiseSome();
Console.ReadKey();
}
}
/// <summary>
/// A consumer class, subscribing twice to the event in it's constructor.
/// </summary>
public class Subscriber
{
public Subscriber(IEventOwner eventOwner)
{
eventOwner.SomeEvent += eventOwner_SomeEvent;
eventOwner.SomeEvent += eventOwner_SomeEvent;
}
void eventOwner_SomeEvent(object sender, EventArgs e)
{
Console.WriteLine(DateTimeOffset.Now);
}
}
/// <summary>
/// This interface is not essensial to this point. it is just added for conveniance.
/// </summary>
public interface IEventOwner
{
event EventHandler<EventArgs> SomeEvent;
void RaiseSome();
}
/// <summary>
/// A traditional event. This is raised for each subscription.
/// </summary>
public class EventOwner1 : IEventOwner
{
public event EventHandler<EventArgs> SomeEvent = delegate { };
public void RaiseSome()
{
SomeEvent(this,new EventArgs());
}
}
/// <summary>
/// A custom event. This is raised only once for each subscriber.
/// </summary>
public class EventOwner2 : IEventOwner
{
private readonly List<EventHandler<EventArgs>> handlers=new List<EventHandler<EventArgs>>();
public event EventHandler<EventArgs> SomeEvent
{
add
{
lock (handlers)
if (handlers!=null&&!handlers.Contains(value))
{
handlers.Add(value);
}
}
remove
{
handlers.Remove(value);
}
}
public void RaiseSome()
{
EventArgs args=new EventArgs();
lock(handlers)
foreach (EventHandler<EventArgs> handler in handlers)
{
handler(this,args);
}
}
}
}
What is the access modifier of 'object'?
If it's private, you only need to worry about the containing object setting the event handler.
If it's internal, you only need to worry about the containing assembly setting the event handler.
If it's public, then it's wide-open.
If 'object' can be made private on the containing class, you can make your checks much more efficient by controlling event handler assignment in the local class.
If 'internal' or 'public' and uniqueness is a requirement, go with a wrapper class that hides 'object' and instead exposes a method for assigning an event handler with your checks behind it to ensure uniqueness.
Related
In my product I need process wide events. For that I used code like this:
public class Global
{
public static event EventHandler<MyEventArgs> Message;
public static void ShowMessage();
}
Now let's say I have a WinForms user interface. In form's code I will subscribe to this event and handle it in some default way (eg. by using System.Windows.Forms.MessageBox.Show() method). Now the question is how do I allow user to create derived form and override my default Message event handler implementation?
Just subscribing to the event for the second time with custom implementation doesn't solve the problem (both event handlers would be executed and potentially two message boxes shown). The options I see are either:
//call OnSubscribeToMessageEvent() from either form's constructor or OnLoad event handler
protected virtual void OnSubscribeToMessageEvent()
{
Global.Message += new EventHandler<MyEventArgs>(Global_Message);
}
private void Global_Message(object sender, MyEventArgs e)
{
//my default implementation
}
or
//subscribe in either form's constructor or OnLoad event handler
protected virtual void Global_Message(object sender, MyEventArgs e)
{
//my default implementation
}
Which version is better and why? Or maybe there are any other options?
I still have some doubts as I have never seen such a design pattern in any .NET library
Yes, you're right to worry about this. These kind of event subscriptions are very fickle, the event source always outlives the subscriber. There's only one class in the framework I know that does this, SystemEvents. The problem is that every subscriber has to very carefully unsubscribe itself when its lifetime ends or the object will stay referenced forever. A memory leak that's very hard to diagnose.
A better pattern here is to use an interface. Let's declare one:
public class MyEventArgs { /* etc.. */ }
public interface IGlobalNotification {
event EventHandler Disposed;
void OnMessage(MyEventArgs arg);
}
Now you can have a form implement the interface:
public partial class Form1 : Form, IGlobalNotification {
public Form1() {
InitializeComponent();
GlobalMessages.Register(this);
}
void IGlobalNotification.OnMessage(MyEventArgs arg) {
// do something
}
}
The Register method registers the form with the GlobalMessages class, the Dispose event ensures that the class can detect that the form is dying:
public static class GlobalMessages {
public static void Register(IGlobalNotification listener) {
listener.Disposed += delegate { listeners.Remove(listener); };
listeners.Add(listener);
}
public static void Notify(MyEventArgs arg) {
foreach (var listener in listeners) listener.OnMessage(arg);
}
private static List<IGlobalNotification> listeners = new List<IGlobalNotification>();
}
Call GlobalMessages.Notify() to get the OnMessage() method to run in all live form instances. The major advantage of this approach is that a client programmer can never screw up.
I would let the derived class override the Global_Message. The subscription to the event is generic and why would you want to implement it in every child again? It also gives you the option to call base.Global_Message(sender, e) in case your child class just wants to add some decoration to it and use the default behaviour otherwise.
I would prefer your second example, as that way, classes that extend your base class only have to override one method and do not have to remove the handler added by the base class from the event.
The key is adding the virtual keyword, so that a derived type can overide the method and the method they created will be called instead.
//subscribe in either form's constructor or OnLoad event handler
protected virtual void Global_Message(object sender, MyEventArgs e)
{
//my default implementation
}
Now that you've added virtual to both, I'd go with the first and override the one that subscribes to the event, if they didn't want the event subscribed to.
Though there is another option, call it #3.
protected EventHandler GlobalMessageEvent = new EventHandler<MyEventArgs>(Global_Message);
protected virtual void OnSubscribeToMessageEvent()
{
// this could be done in the Form_Load() or constructor instead.
Global.Message += GlobalMessageEvent;
}
Then potentially an inherited class could do somewhere: (note the -=)
{
Global.Message -= GlobalMessageEvent;
}
Quote from:
http://msdn.microsoft.com/en-us/library/aa645739(VS.71).aspx
"Invoking an event can only be done from within the class that declared the event."
I am puzzled why there is such restriction. Without this limitation I would be able to write a class (one class) which once for good manages sending the events for a given category -- like INotifyPropertyChanged.
With this limitation I have to copy and paste the same (the same!) code all over again. I know that designers of C# don't value code reuse too much (*), but gee... copy&paste. How productive is that?
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
In every class changing something, to the end of your life. Scary!
So, while I am reverting my extra sending class (I am too gullible) to old, "good" copy&paste way, can you see
what terrible could happen with the ability to send events for a sender?
If you know any tricks how to avoid this limitation -- don't hesitate to answer as well!
(*) with multi inheritance I could write universal sender once for good in even clearer manner, but C# does not have multi inheritance
Edits
The best workaround so far
Introducing interface
public interface INotifierPropertyChanged : INotifyPropertyChanged
{
void OnPropertyChanged(string property_name);
}
adding new extension method Raise for PropertyChangedEventHandler. Then adding mediator class for this new interface instead of basic INotifyPropertyChanged.
So far it is minimal code that let's send you message from nested object in behalf of its owner (when owner required such logic).
THANK YOU ALL FOR THE HELP AND IDEAS.
Edit 1
Guffa wrote:
"You couldn't cause something to happen by triggering an event from the outside,"
It is interesting point, because... I can. It is exactly why I am asking. Take a look.
Let's say you have class string. Not interesting, right? But let's pack it with Invoker class, which send events every time it changed.
Now:
class MyClass : INotifyPropertyChanged
{
public SuperString text { get; set; }
}
Now, when text is changed MyClass is changed. So when I am inside text I know, that if only I have owner, it is changed as well. So I could send event on its behalf. And it would be semantically 100% correct.
Remark: my class is just a bit smarter -- owner sets if it would like to have such logic.
Edit 2
Idea with passing the event handler -- "2" won't be displayed.
public class Mediator
{
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string property_name)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(property_name));
}
public void Link(PropertyChangedEventHandler send_through)
{
PropertyChanged += new PropertyChangedEventHandler((obj, args) => {
if (send_through != null)
send_through(obj, args);
});
}
public void Trigger()
{
OnPropertyChanged("hello world");
}
}
public class Sender
{
public event PropertyChangedEventHandler PropertyChanged;
public Sender(Mediator mediator)
{
PropertyChanged += Listener1;
mediator.Link(PropertyChanged);
PropertyChanged += Listener2;
}
public void Listener1(object obj, PropertyChangedEventArgs args)
{
Console.WriteLine("1");
}
public void Listener2(object obj, PropertyChangedEventArgs args)
{
Console.WriteLine("2");
}
}
static void Main(string[] args)
{
var mediator = new Mediator();
var sender = new Sender(mediator);
mediator.Trigger();
Console.WriteLine("EOT");
Console.ReadLine();
}
Edit 3
As an comment to all argument about misuse of direct event invoking -- misuse is of course still possible. All it takes is implementing the described above workaround.
Edit 4
Small sample of my code (end use), Dan please take a look:
public class ExperimentManager : INotifierPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string property_name)
{
PropertyChanged.Raise(this, property_name);
}
public enum Properties
{
NetworkFileName,
...
}
public NotifierChangedManager<string> NetworkFileNameNotifier;
...
public string NetworkFileName
{
get { return NetworkFileNameNotifier.Value; }
set { NetworkFileNameNotifier.Value = value; }
}
public ExperimentManager()
{
NetworkFileNameNotifier =
NotifierChangedManager<string>.CreateAs(this, Properties.NetworkFileName.ToString());
...
}
Think about it for a second before going off on a rant. If any method could invoke an event on any object, would that not break encapsulation and also be confusing? The point of events is so that instances of the class with the event can notify other objects that some event has occurred. The event has to come from that class and not from any other. Otherwise, events become meaningless because anyone can trigger any event on any object at any time meaning that when an event fires, you don't know for sure if it's really because the action it represents took place, or just because some 3rd party class decided to have some fun.
That said, if you want to be able to allow some sort of mediator class send events for you, just open up the event declaration with the add and remove handlers. Then you could do something like this:
public event PropertyChangedEventHandler PropertyChanged {
add {
propertyChangedHelper.PropertyChanged += value;
}
remove {
propertyChangedHelper.PropertyChanged -= value;
}
}
And then the propertyChangedHelper variable can be an object of some sort that'll actually fire the event for the outer class. Yes, you still have to write the add and remove handlers, but it's fairly minimal and then you can use a shared implementation of whatever complexity you want.
Allowing anyone to raise any event puts us in this problem:
#Rex M: hey everybody, #macias just raised his hand!
#macias: no, I didn't.
#everyone: too late! #Rex M said you did, and we all took action believing it.
This model is to protect you from writing applications that can easily have invalid state, which is one of the most common sources of bugs.
I think you're misunderstanding the restriction. What this is trying to say is that only the class which declared the event should actually cause it to be raised. This is different than writing a static helper class to encapsulate the actual event handler implementation.
A class A that is external to the class which declares the event B should not be able to cause B to raise that event directly. The only way A should have to cause B to raise the event is to perform some action on B which, as a result of performing that action raises the event.
In the case of INotifyPropertyChanged, given the following class:
public class Test : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string name;
public string Name
{
get { return this.name; }
set { this.name = value; OnNotifyPropertyChanged("Name"); }
}
protected virtual void OnPropertyChanged(string name)
{
PropertyChangedEventHandler temp = PropertyChanged;
if (temp!= null)
{
temp(this, new PropertyChangedEventArgs(name));
}
}
}
The only way for a class consuming Test to cause Test to raise the PropertyChanged event is by setting the Name property:
public void TestMethod()
{
Test t = new Test();
t.Name = "Hello"; // This causes Test to raise the PropertyChanged event
}
You would not want code that looked like:
public void TestMethod()
{
Test t = new Test();
t.Name = "Hello";
t.OnPropertyChanged("Name");
}
All of that being said, it is perfectly acceptable to write a helper class which encapsualtes the actual event handler implementation. For example, given the following EventManager class:
/// <summary>
/// Provides static methods for event handling.
/// </summary>
public static class EventManager
{
/// <summary>
/// Raises the event specified by <paramref name="handler"/>.
/// </summary>
/// <typeparam name="TEventArgs">
/// The type of the <see cref="EventArgs"/>
/// </typeparam>
/// <param name="sender">
/// The source of the event.
/// </param>
/// <param name="handler">
/// The <see cref="EventHandler{TEventArgs}"/> which
/// should be called.
/// </param>
/// <param name="e">
/// An <see cref="EventArgs"/> that contains the event data.
/// </param>
public static void OnEvent<TEventArgs>(object sender, EventHandler<TEventArgs> handler, TEventArgs e)
where TEventArgs : EventArgs
{
// Make a temporary copy of the event to avoid possibility of
// a race condition if the last subscriber unsubscribes
// immediately after the null check and before the event is raised.
EventHandler<TEventArgs> tempHandler = handler;
// Event will be null if there are no subscribers
if (tempHandler != null)
{
tempHandler(sender, e);
}
}
/// <summary>
/// Raises the event specified by <paramref name="handler"/>.
/// </summary>
/// <param name="sender">
/// The source of the event.
/// </param>
/// <param name="handler">
/// The <see cref="EventHandler"/> which should be called.
/// </param>
public static void OnEvent(object sender, EventHandler handler)
{
OnEvent(sender, handler, EventArgs.Empty);
}
/// <summary>
/// Raises the event specified by <paramref name="handler"/>.
/// </summary>
/// <param name="sender">
/// The source of the event.
/// </param>
/// <param name="handler">
/// The <see cref="EventHandler"/> which should be called.
/// </param>
/// <param name="e">
/// An <see cref="EventArgs"/> that contains the event data.
/// </param>
public static void OnEvent(object sender, EventHandler handler, EventArgs e)
{
// Make a temporary copy of the event to avoid possibility of
// a race condition if the last subscriber unsubscribes
// immediately after the null check and before the event is raised.
EventHandler tempHandler = handler;
// Event will be null if there are no subscribers
if (tempHandler != null)
{
tempHandler(sender, e);
}
}
}
It's perfectly legal to change Test as follows:
public class Test : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string name;
public string Name
{
get { return this.name; }
set { this.name = value; OnNotifyPropertyChanged("Name"); }
}
protected virtual void OnPropertyChanged(string name)
{
EventHamanger.OnEvent(this, PropertyChanged, new PropertyChangedEventArgs(name));
}
}
First of all I must say, events are actually meant to be invoked from within the object only when any external eventhandler is attached to it.
So basically, the event gives you a callback from an object and gives you a chance to set the handler to it so that when the event occurs it automatically calls the method.
This is similar of sending a value of variable to a member. You can also define a delegate and send the handler the same way. So basically its the delegate that is assigned the function body and eventually when the class invokes the event, it will call the method.
If you dont want to do stuffs like this on every class, you can easily create an EventInvoker which defines each of them, and in the constructor of it you pass the delegate.
public class EventInvoker
{
public EventInvoker(EventHandler<EventArgs> eventargs)
{
//set the delegate.
}
public void InvokeEvent()
{
// Invoke the event.
}
}
So basically you create a proxy class on each of those methods and making this generic will let you invoke events for any event. This way you can easily avoid making call to those properties every time.
Events are intended for being notified that something has happened. The class where event is declared takes care of triggering the event at the right time.
You couldn't cause something to happen by triggering an event from the outside, you would only cause every event subscriber to think that it had happened. The correct way to make something happen is to actually make it happen, not to make it look like it happened.
So, allowing events to be triggered from outside the class can almost only be misused. On the off chance that triggering an event from the outside would be useful for some reason, the class can easily provide a method that allows it.
Update
OK, before we go any further, we definitely need to clarify a certain point.
You seem to want this to happen:
class TypeWithEvents
{
public event PropertyChangedEventHandler PropertyChanged;
// You want the set method to automatically
// raise the PropertyChanged event via some
// special code in the EventRaisingType class?
public EventRaisingType Property { get; set; }
}
Do you really want to be able to write your code just like this? This is really totally impossible -- at least in .NET (at least until the C# team comes up with some fancy new syntactic sugar specifically for the INotifyPropertyChanged interface, which I believe has actually been discussed) -- as an object has no notion of "the variables that have been assigned to me." In fact there is really no way to represent a variable using an object at all (I suppose LINQ expressions is a way, actually, but that's a totally different subject). It only works the opposite way. So let's say you have:
Person x = new Person("Bob");
x = new Person("Sam");
Does "Bob" know x just got assigned to "Sam"? Absolutely not: the variable x just pointed to "Bob", it never was "Bob"; so "Bob" doesn't know or care one lick about what happens with x.
Thus an object couldn't possibly hope to perform some action based on when a variable pointing to it gets changed to point at something else. It would be as if you wrote my name and address on an envelope, and then you erased it and wrote somebody else's name, and I somehow magically knew, #macias just changed the address on an envelope from mine to someone else's!
Of course, what you can do is modify a property so that its get and set methods modify a different property of a private member, and link your events to an event supplied by that member (this is essentially what siride has suggested). In this scenario it would be kind of reasonable to desire the functionality you're asking about. This is the scenario that I have in mind in my original answer, which follows.
Original Answer
I wouldn't say that what you're asking for is just flat-out wrong, as some others seem to be suggesting. Obviously there could be benefits to allowing a private member of a class to raise one of that class's events, such as in the scenario you've described. And while saurabh's idea is a good one, clearly, it cannot always be applied since C# lacks multiple inheritance*.
Which gets me to my point. Why doesn't C# allow multiple inheritance? I know this might seem off-topic, but the answers to this and that question are the same. It isn't that it's illegal because it would "never" make sense; it's illegal because there are simply more cons than pros. Multiple inheritance is very hard to get right. Similarly, the behavior you are describing would be very easy to abuse.
That is, yes, the general case Rex has described makes a pretty good argument against objects raising other objects' events. The scenario you've described, on the other hand -- the constant repetition of boilerplate code -- seems to make something of a case in favor of this behavior. The question is: which consideration should be given greater weight?
Let's say the .NET designers decided to allow this, and simply hope that developers would not abuse it. There would almost certainly be a lot more broken code out there where the designer of class X did not anticipate that event E would be raised by class Y, way off in another assembly. But it does, and the X object's state becomes invalid, and subtle bugs creep in everywhere.
What about the opposite scenario? What if they disallowed it? Now of course we're just considering reality, because this is the case. But what is the huge downside here? You have to copy and paste the same code in a bunch of places. Yes, it's annoying; but also, there are ways to mitigate this (such as saurabh's base class idea). And the raising of events is strictly defined by the declaring type, always, which gives us much greater certainty about the behavior of our programs.
So:
EVENT POLICY | PROS | CONS
------------------------------+---------------------+-------------------------
Allowing any object to raise | Less typing in | Far less control over
another object's event | certain cases | class behavior, abun-
| | dance of unexpected
| | scenarios, proliferation
| | of subtle bugs
| |
------------------------------------------------------------------------------
Restricting events to be only | Much better control | More typing required
raised by the declaring type | of class behavior, | in some cases
| no unexpected |
| scenarios, signifi- |
| cant decrease in |
| bug count |
Imagine you're responsible for deciding which event policy to implement for .NET. Which one would you choose?
*I say "C#" rather than ".NET" because I'm actually not sure if the prohibition on multiple inheritance is a CLR thing, or just a C# thing. Anybody happen to know?
This question already has answers here:
Checking for null before event dispatching... thread safe?
(6 answers)
Closed 2 years ago.
In order to raise an event we use a method OnEventName like this:
protected virtual void OnSomethingHappened(EventArgs e)
{
EventHandler handler = SomethingHappened;
if (handler != null)
{
handler(this, e);
}
}
But what is the difference with this one ?
protected virtual void OnSomethingHappened(EventArgs e)
{
if (SomethingHappened!= null)
{
SomethingHappened(this, e);
}
}
Apparently the first is thread-safe, but why and how ?
It's not necessary to start a new thread ?
There is a tiny chance that SomethingHappened becomes null after the null check but before the invocation. However, MulticastDelagates are immutable, so if you first assign a variable, null check against the variable and invoke through it, you are safe from that scenario (self plug: I wrote a blog post about this a while ago).
There is a back side of the coin though; if you use the temp variable approach, your code is protected against NullReferenceExceptions, but it could be that the event will invoke event listeners after they have been detached from the event. That is just something to deal with in the most graceful way possible.
In order to get around this I have an extension method that I sometimes use:
public static class EventHandlerExtensions
{
public static void SafeInvoke<T>(this EventHandler<T> evt, object sender, T e) where T : EventArgs
{
if (evt != null)
{
evt(sender, e);
}
}
}
Using that method, you can invoke the events like this:
protected void OnSomeEvent(EventArgs e)
{
SomeEvent.SafeInvoke(this, e);
}
Since C# 6.0 you can use monadic Null-conditional operator ?. to check for null and raise events in easy and thread-safe way.
SomethingHappened?.Invoke(this, args);
It’s thread-safe because it evaluates the left-hand side only once, and keeps it in a temporary variable. You can read more here in part titled Null-conditional operators.
Update:
Actually Update 2 for Visual Studio 2015 now contains refactoring to simplify delegate invocations that will end up with exactly this type of notation. You can read about it in this announcement.
I keep this snippet around as a reference for safe multithreaded event access for both setting and firing:
/// <summary>
/// Lock for SomeEvent delegate access.
/// </summary>
private readonly object someEventLock = new object();
/// <summary>
/// Delegate variable backing the SomeEvent event.
/// </summary>
private EventHandler<EventArgs> someEvent;
/// <summary>
/// Description for the event.
/// </summary>
public event EventHandler<EventArgs> SomeEvent
{
add
{
lock (this.someEventLock)
{
this.someEvent += value;
}
}
remove
{
lock (this.someEventLock)
{
this.someEvent -= value;
}
}
}
/// <summary>
/// Raises the OnSomeEvent event.
/// </summary>
public void RaiseEvent()
{
this.OnSomeEvent(EventArgs.Empty);
}
/// <summary>
/// Raises the SomeEvent event.
/// </summary>
/// <param name="e">The event arguments.</param>
protected virtual void OnSomeEvent(EventArgs e)
{
EventHandler<EventArgs> handler;
lock (this.someEventLock)
{
handler = this.someEvent;
}
if (handler != null)
{
handler(this, e);
}
}
For .NET 4.5 it's better to use Volatile.Read to assign a temp variable.
protected virtual void OnSomethingHappened(EventArgs e)
{
EventHandler handler = Volatile.Read(ref SomethingHappened);
if (handler != null)
{
handler(this, e);
}
}
Update:
It's explained in this article: http://msdn.microsoft.com/en-us/magazine/jj883956.aspx. Also, it was explained in Fourth edition of "CLR via C#".
Main idea is that JIT compiler can optimize your code and remove the local temporary variable. So this code:
protected virtual void OnSomethingHappened(EventArgs e)
{
EventHandler handler = SomethingHappened;
if (handler != null)
{
handler(this, e);
}
}
will be compiled into this:
protected virtual void OnSomethingHappened(EventArgs e)
{
if (SomethingHappened != null)
{
SomethingHappened(this, e);
}
}
This happens in certain special circumstances, however it can happen.
It depends on what you mean by thread-safe. If your definition only includes the prevention of the NullReferenceException then the first example is more safe. However, if you go with a more strict definition in which the event handlers must be invoked if they exist then neither is safe. The reason has to do with the complexities of the memory model and barriers. It could be that there are, in fact, event handlers chained to the delegate, but the thread always reads the reference as null. The correct way of fixing both is to create an explicit memory barrier at the point the delegate reference is captured into a local variable. There are several ways of doing this.
Use the lock keyword (or any synchronization mechanism).
Use the volatile keyword on the event variable.
Use Thread.MemoryBarrier.
Despite the awkward scoping problem which prevents you from doing the one-line initializer I still prefer the lock method.
protected virtual void OnSomethingHappened(EventArgs e)
{
EventHandler handler;
lock (this)
{
handler = SomethingHappened;
}
if (handler != null)
{
handler(this, e);
}
}
It is important to note that in this specific case the memory barrier problem is probably moot because it is unlikely that reads of variables will be lifted outside method calls. But, there is no guarentee especially if the compiler decides to inline the method.
Declare your event like this to get thread safety:
public event EventHandler<MyEventArgs> SomethingHappened = delegate{};
And invoke it like this:
protected virtual void OnSomethingHappened(MyEventArgs e)
{
SomethingHappened(this, e);
}
Although the method is not needed anymore..
Update 2021-09-01
Today I would simply do (which do not require the emty delegate):
SomethingHappened?.Invoke(e);
Someone pointed out that using an empty delegate has a larger overhead. That's true. But from an application perspetive, the performance impact is minimal. Therefore, it's much more important to choose the solution that has the cleanest code.
Actually, the first is thread-safe, but the second isn't. The problem with the second is that the SomethingHappened delegate could be changed to null between the null verification and the invocation. For a more complete explanation, see http://blogs.msdn.com/b/ericlippert/archive/2009/04/29/events-and-races.aspx.
Actually, no, the second example isn't considered thread-safe. The SomethingHappened event could evaluate to non-null in the conditional, then be null when invoked. It's a classic race condition.
I tried to pimp out Jesse C. Slicer's answer with:
Ability to sub/unsubscribe from any thread while within a raise (race condition removed)
Operator overloads for += and -= at the class level
Generic caller defined delegates
public class ThreadSafeEventDispatcher<T> where T : class
{
readonly object _lock = new object();
private class RemovableDelegate
{
public readonly T Delegate;
public bool RemovedDuringRaise;
public RemovableDelegate(T #delegate)
{
Delegate = #delegate;
}
};
List<RemovableDelegate> _delegates = new List<RemovableDelegate>();
Int32 _raisers; // indicate whether the event is being raised
// Raises the Event
public void Raise(Func<T, bool> raiser)
{
try
{
List<RemovableDelegate> raisingDelegates;
lock (_lock)
{
raisingDelegates = new List<RemovableDelegate>(_delegates);
_raisers++;
}
foreach (RemovableDelegate d in raisingDelegates)
{
lock (_lock)
if (d.RemovedDuringRaise)
continue;
raiser(d.Delegate); // Could use return value here to stop.
}
}
finally
{
lock (_lock)
_raisers--;
}
}
// Override + so that += works like events.
// Adds are not recognized for any event currently being raised.
//
public static ThreadSafeEventDispatcher<T> operator +(ThreadSafeEventDispatcher<T> tsd, T #delegate)
{
lock (tsd._lock)
if (!tsd._delegates.Any(d => d.Delegate == #delegate))
tsd._delegates.Add(new RemovableDelegate(#delegate));
return tsd;
}
// Override - so that -= works like events.
// Removes are recongized immediately, even for any event current being raised.
//
public static ThreadSafeEventDispatcher<T> operator -(ThreadSafeEventDispatcher<T> tsd, T #delegate)
{
lock (tsd._lock)
{
int index = tsd._delegates
.FindIndex(h => h.Delegate == #delegate);
if (index >= 0)
{
if (tsd._raisers > 0)
tsd._delegates[index].RemovedDuringRaise = true; // let raiser know its gone
tsd._delegates.RemoveAt(index); // okay to remove, raiser has a list copy
}
}
return tsd;
}
}
Usage:
class SomeClass
{
// Define an event including signature
public ThreadSafeEventDispatcher<Func<SomeClass, bool>> OnSomeEvent =
new ThreadSafeEventDispatcher<Func<SomeClass, bool>>();
void SomeMethod()
{
OnSomeEvent += HandleEvent; // subscribe
OnSomeEvent.Raise(e => e(this)); // raise
}
public bool HandleEvent(SomeClass someClass)
{
return true;
}
}
Any major problems with this approach?
The code was only briefly tested and edited a bit on insert.
Pre-acknowledge that List<> not a great choice if many elements.
For either of these to be thread safe, you are assuming that all the objects that subscribe to the event are also thread safe.
In my class I want to declare an event that other classes can subscribe to. What is the correct way to declare the event?
This doesn't work:
public event CollectMapsReportingComplete;
You forgot to mention the type. For really simple events, EventHandler might be enough:
public event EventHandler CollectMapsReportingComplete;
Sometimes you will want to declare your own delegate type to be used for your events, allowing you to use a custom type for the EventArgs parameter (see Adam Robinson's comment):
public delegate void CollectEventHandler(object source, MapEventArgs args);
public class MapEventArgs : EventArgs
{
public IEnumerable<Map> Maps { get; set; }
}
You can also use the generic EventHandler type instead of declaring your own types:
public event EventHandler<MapEventArgs> CollectMapsReportingComplete;
You need to specify the delegate type the event:
public event Action CollectMapsReportingComplete;
Here I have used System.Action but you can use any delegate type you wish (even a custom delegate). An instance of the delegate type you specify will be used as the backing field for the event.
An Example
/// </summary>
/// Event triggered when a search is entered in any <see cref="SearchPanel"/>
/// </summary>
public event EventHandler<string> SearchEntered
{
add { searchevent += value; }
remove { searchevent -= value; }
}
private event EventHandler<string> searchevent;
public event EventHandler MyEvent;
public event [DelegateType] [EventName];
This question already has answers here:
How to ensure an event is only subscribed to once
(8 answers)
Closed 8 years ago.
Duplicate of: How to ensure an event is only subscribed to once
and Has an event handler already been added?
I have a singleton that provides some service and my classes hook into some events on it, sometimes a class is hooking twice to the event and then gets called twice.
I'm looking for a classical way to prevent this from happening. somehow I need to check if I've already hooked to this event...
How about just removing the event first with -= , if it is not found an exception is not thrown
/// -= Removes the event if it has been already added, this prevents multiple firing of the event
((System.Windows.Forms.WebBrowser)sender).Document.Click -= new System.Windows.Forms.HtmlElementEventHandler(testii);
((System.Windows.Forms.WebBrowser)sender).Document.Click += new System.Windows.Forms.HtmlElementEventHandler(testii);
Explicitly implement the event and check the invocation list. You'll also need to check for null:
using System.Linq; // Required for the .Contains call below:
...
private EventHandler foo;
public event EventHandler Foo
{
add
{
if (foo == null || !foo.GetInvocationList().Contains(value))
{
foo += value;
}
}
remove
{
foo -= value;
}
}
Using the code above, if a caller subscribes to the event multiple times, it will simply be ignored.
I've tested each solution and the best one (considering performance) is:
private EventHandler _foo;
public event EventHandler Foo {
add {
_foo -= value;
_foo += value;
}
remove {
_foo -= value;
}
}
No Linq using required. No need to check for null before cancelling a subscription (see MS EventHandler for details). No need to remember to do the unsubscription everywhere.
You really should handle this at the sink level and not the source level. That is, don't prescribe event handler logic at the event source - leave that to the handlers (the sinks) themselves.
As the developer of a service, who are you to say that sinks can only register once? What if they want to register twice for some reason? And if you are trying to correct bugs in the sinks by modifying the source, it's again a good reason for correcting these issues at the sink-level.
I'm sure you have your reasons; an event source for which duplicate sinks are illegal is not unfathomable. But perhaps you should consider an alternate architecture that leaves the semantics of an event intact.
You need to implement the add and remove accessors on the event, and then check the target list of the delegate, or store the targets in a list.
In the add method, you can use the Delegate.GetInvocationList method to obtain a list of the targets already added to the delegate.
Since delegates are defined to compare equal if they're linked to the same method on the same target object, you could probably run through that list and compare, and if you find none that compares equal, you add the new one.
Here's sample code, compile as console application:
using System;
using System.Linq;
namespace DemoApp
{
public class TestClass
{
private EventHandler _Test;
public event EventHandler Test
{
add
{
if (_Test == null || !_Test.GetInvocationList().Contains(value))
_Test += value;
}
remove
{
_Test -= value;
}
}
public void OnTest()
{
if (_Test != null)
_Test(this, EventArgs.Empty);
}
}
class Program
{
static void Main()
{
TestClass tc = new TestClass();
tc.Test += tc_Test;
tc.Test += tc_Test;
tc.OnTest();
Console.In.ReadLine();
}
static void tc_Test(object sender, EventArgs e)
{
Console.Out.WriteLine("tc_Test called");
}
}
}
Output:
tc_Test called
(ie. only once)
Microsoft's Reactive Extensions (Rx) framework can also be used to do "subscribe only once".
Given a mouse event foo.Clicked, here's how to subscribe and receive only a single invocation:
Observable.FromEvent<MouseEventArgs>(foo, nameof(foo.Clicked))
.Take(1)
.Subscribe(MyHandler);
...
private void MyHandler(IEvent<MouseEventArgs> eventInfo)
{
// This will be called just once!
var sender = eventInfo.Sender;
var args = eventInfo.EventArgs;
}
In addition to providing "subscribe once" functionality, the RX approach offers the ability to compose events together or filter events. It's quite nifty.
Create an Action instead of an event. Your class may look like:
public class MyClass
{
// sender arguments <----- Use this action instead of an event
public Action<object, EventArgs> OnSomeEventOccured;
public void SomeMethod()
{
if(OnSomeEventOccured!=null)
OnSomeEventOccured(this, null);
}
}
have your singleton object check it's list of who it notifies and only call once if duplicated. Alternatively if possible reject event attachment request.
In silverlight you need to say e.Handled = true; in the event code.
void image_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
e.Handled = true; //this fixes the double event fire problem.
string name = (e.OriginalSource as Image).Tag.ToString();
DoSomething(name);
}
Please tick me if this helps.