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?
Related
I'd like to find how to separate my GUI and work code.
The contrived example code, below, is the smallest starting point that
I can think of that covers the idea.
The example uses a Windows Form as the source of commands and as display
(consumer) of results. I want the work code to be capable of getting commands from, say, a command line interface instead. The work code should not depend on knowledge of the Form. The Form should know little about the work code. I'd like to have several consumers "see" when the property in the work code changes value.
I'm guessing this means using events for communication, and perhaps Interfaces as well, but I'm open to anything.
There are a million different suggestions out there. I've read the design pattern books, and I have tried many, and have yet to find a set that is well enough explained that I can fully implement it.
I don't want a universal solution. I want one as simple as possible
to implement and maintain for small, personal projects. I'm not
designing for a large corporation.
Most solutions I've found will hint at what to do, but not cover
the specifics like where an event is declared, and how the other
piece of code finds out about the event's existence so it can either issue
the event or respond to the event. I always end up needing, somewhere, what amounts to a global variable to hook things together.
The closest match I can find, here, to my question is this: C# Windows Forms App: Separate GUI from Business Logic But the solution uses the form to create an instance of the worker and returns a value directly, rather than informing any interested observers. The provided solution tightly bound the two classes.
The closest solution I've found anywhere is this: https://www.codeproject.com/Articles/14660/WinForms-Model-View-Presenter
which does some really cool work with interfaces and reflection, but didn't seem too maintainable nor flexible.
The comment lines in the source code below show the desired interaction
points but without the implementation.
File #1:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
// tell an instance of JustCounts to increment by 10
}
// Here, allow JustCounts to cause a call to this (or something
// similar, perhaps a property) to inform this code that the TotalCount
// property has changed.
public void ShowNewTotalCount(int NewTotal)
{
Console.WriteLine("New Total Count = {0}", NewTotal);
}
}
File #2
class JustCounts
{
private int m_TotalCount = 100;
// Inform other classes when the following property changes value,
// preferably including the value in the notification.
public int TotalCount { get => m_TotalCount; }
// The code in File #1 needs to result in a call to this method
// along with the correct argument value.
public void AddThisMuch(int increment)
{
m_TotalCount += increment;
}
}
I'm basing this on the current version of .Net (4.6.2).
If we implement INotifyPropertyChanged then we have an event that we can listen to for property changes. A bit like listening for key presses, we can filter then for the specific property that we want.
public class JustCounts : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private int m_totalCount = 100;
public int TotalCount
{
get { return m_totalCount; }
set
{
if (value != m_totalCount)
{
m_totalCount = value;
NotifyPropertyChanged();
}
}
}
}
There's no need to create a method to manipulate the TotalCount property as we're exposing it.
public class Form1 : Form
{
// justCounts is a reference to the object wherever it is coming from
justCounts.PropertyChanged += new PropertyChangedEventHandler(JustCountsChangedHandler);
private void JustCountsChangedHandler(object sender, PropertyChangingEventArgs e)
{
// process on event firing
Debug.WriteLine($"justCounts TotalCount changed value to {justCounts.TotalCount}");
}
// Example of where the handler will fire when called
private void button1_click(object sender, EventArgs e)
{
justCounts.TotalCount++;
}
}
In the code above, we've created an event in JustCounts to which listeners can subscribe.
Using the INotifyPropertyChanged interface, we fire the event each time TotalCount is changed.
In form 1 we create the handler to listen for property changes, and the handler then carries out any processing.
One note. You say
I'd like to have several consumers "see" when the property in the work
code changes value
so in order for this to work we have to assume that the work code can run independently of it's subscriber (something like a server). Otherwise, we'd have different instances for different subscribers.
You also mention interfaces, and they could be used but are not necessary in this instance.
Clarifications:
1.- I don't know if this has an specific name or word to reference it in English or programming slang, so maybe this can be a duplicate post, since I'm can't look about it.
2.- I'm totally newbie with this stuff, I've never used handlers, so that's part of the problem.
I'm trying to understand how the NotifyPropertyChanged mechanism works. Based on: INotifyPropertyChanged, focusing on the example. (I'm looking it in Spanish, above you can change it to the original English one if it doesn't change auto.
Now I'm going to extract the main code that makes me wonder, and try to analyze it. Hope you can show me where (if exist) i'm wrong and what I can't understand. Let's focus on the class that implements the interface.
// This is a simple customer class that
// implements the IPropertyChange interface.
public class DemoCustomer : INotifyPropertyChanged
{
// These fields hold the values for the public properties.
private Guid idValue = Guid.NewGuid();
private string customerNameValue = String.Empty;
private string phoneNumberValue = String.Empty;
public event PropertyChangedEventHandler PropertyChanged;
// This method is called by the Set accessor of each property.
// The CallerMemberName attribute that is applied to the optional propertyName
// parameter causes the property name of the caller to be substituted as an argument.
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
// The constructor is private to enforce the factory pattern.
private DemoCustomer()
{
customerNameValue = "Customer";
phoneNumberValue = "(312)555-0100";
}
// This is the public factory method.
public static DemoCustomer CreateNewCustomer()
{
return new DemoCustomer();
}
// This property represents an ID, suitable
// for use as a primary key in a database.
public Guid ID
{
get
{
return this.idValue;
}
}
public string CustomerName
{
get
{
return this.customerNameValue;
}
set
{
if (value != this.customerNameValue)
{
this.customerNameValue = value;
NotifyPropertyChanged();
}
}
}
public string PhoneNumber
{
get
{
return this.phoneNumberValue;
}
set
{
if (value != this.phoneNumberValue)
{
this.phoneNumberValue = value;
NotifyPropertyChanged();
}
}
}
Well, what do I understand? (or believe it).
From:
public event PropertyChangedEventHandler PropertyChanged;
1.- PropertyChanged is a method. The one which would be executed when ProperyChanged event triggers.
Doubt: But this method is never implemented...
From:
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
2.- NotifyPropertyChanged is a method. Created by us, can have any name we desire. This method will be launched by us when a property gets modified.
Question: Does this method triggers ProperyChanged event?
Doubt: For me, as I can see there, no one launches this event, but the method we've created to be launch when triggers. But since it doesn't triggers, and instead of it we directly launch the method...
Mixture final think: NotifyPropertyChanged throws the event using the Hanlder, in order to be caught by the "superior entity" (the binding source in the example code), which receives the modified property in order to can update it. Then, if I want to know which elements/classes can be aware of this kind of events, what can I do?
I think this last one is the correct one, but since I'm not and expert but my thinking while trying to understand it and writing this question, I'd like you to correct me.
Thanks so much!
UPDATED
Thanks so much to all! Then, Can I suscribe to the event with the method i want? I've tried:
objetos[usados] = new ItemDB();
objetos[usados].PropertyChanged += mensaje();
With:
public async void mensaje(string cadena)
{
var dlg = new ContentDialog(){
Title = "My App",
Content = cadena,
PrimaryButtonText = "Yes",
SecondaryButtonText = "No"
};
var result = await dlg.ShowAsync();
}
But then VS says:
Error 1 Ninguna sobrecarga correspondiente a 'mensaje' coincide con el 'System.ComponentModel.PropertyChangedEventHandler' delegado
Translated:
Error 1 No one overload corresponding to 'mensaje' matches with 'System.ComponentModel.PropertyChangedEventHandler' delegate
Why doesn't it work, since my event is given with an arg that is a string, and mensaje receives as an argument and string?
I recommend you look up Events and Delegates in C# for further reading.
public event PropertyChangedEventHandler PropertyChanged;
PropertyChanged ist an EventHandler, which is a delegate. Other code can register here and get executed when the delegate is called.
So what happens with INotifyPropertyChanged is:
Some Code (propably the binding in Xaml) registers for the PropertyChanged event:
yourobject.PropertyChanged += MethodThatShouldBeCalledWhenThePropertyChanges;
(This is most properly auto generated somewhere, because it happens from xaml, but you could as well to it this way by hand.)
In the NotifyPropertyChanged Method, the event delegate gets executed.
It simply executes all methods that were added to the event.
So to answer your questions:
Yes, the code in NotifyPropertyChanged "triggers" the event. It calls every method that was added to the event.
Any code can register for events.
As of your Update:
I again recommend reading into delegates.
You can think of delegates as Method Interface. It defines that a method has to take specific parameter types to match the delegate.
PropertyChanged is of type PropertyChangedEventHandler which takes an object and a PropertyChangedEventArgs parameter.
So any method like this is suitable:
void MethodName(
Object sender,
PropertyChangedEventArgs e
)
First, you are correct, NotifyPropertyChanged is a user-defined function. It is indented just to avoid doubling of logic as soon as more properties are used. Second, NotifyPropertyChanged will not be executed when the event triggers, but the other way round; as soon as NotifyPropertyChanged is called, the event is triggered. If a suitable control is bound, it will, so to speak, consume the event and probably update itself. The event can be seen as an outlet on which other code can register callbacks. Furthermore, the Attribute CallerMemberName was introduced with .NET 4.5. The same result can be achieved without using it, but for each call of NotifyPropertyChanged the name of the property would have to be given explicitly.
Okay, I've been searching on the site and Google and can't quite get my head around where things need to be in terms of delegates and eventhandlers and the like so hopefully someone here can help/explain what I need to do.
So, I am writing a simple database application (using SQLite). There is a mainform that is the MDI parent (that's basically a big window with menus at the top). The menus launch other windows that allow view, edit and insert into various tables of the database.
One of those windows is a LOG window which shows my log table.
At the moment, if a user changes something in the window showing the data in TABLE. The operation also writes into the log table. If the Log window is open, however, the log view doesn't update.
So, I've figured out I probably need to 'fire' an event from my TABLE UPDATE code that my LOG window 'subscribes' to (so it can update the DataGridView).
What I can't figure out is where the different 'bits' of the event go.
Should the MdiParent have the public delegate void EventHandler();? If not where?
which class gets the public static event EventHandler logGoneStale;?
The only bit I'm reasonably sure about is that the Window that displays the log (which has a method called public void UpdateLogDataGridView() - which calls the database object/methods to (re-)populate the datagridview) needs to have:
something like logGoneStale += new EventHandler(UpdateLogDataGridView); in it. Is that at least right?
Totally befuddled - it seems none of the event examples/tutorials on MSDN are trying to do what I want to achieve.
You need to define an event in the class that is sending the event, and append an event handler in the class that should receive the event. To make things slightly easier, starting with C# 3.5 you can forget about the delegate keyword altogether and use a lamba expression as event handler. Also note that it in most cases it makes no sense to make an event static, since usually events are fired by an instance, not by a class.
Example:
class SendsEvent
{
public event EventHandler MyEvent;
public void FireEvent()
{
if(MyEvent != null) // MyEvent is null if no handlers have been attached
{
MyEvent(this, new EventArgs()); // event fired here
}
}
}
class ReceivesEvent
{
private SendsEvent eventSource;
public ReceivesEvent(SendsEvent eventSource)
{
this.eventSource = eventSource;
// Attach event handler - can be a lambda expression
// or method with signature
// "void HandleEvent(object sender, EventArgs e)"
this.eventSource.MyEvent += (sender, args) =>
{
// do something when event was fired
Console.Out.WriteLine("Hello. Event was fired.");
};
}
}
class Program
{
public static void Main()
{
var eventSource = new SendsEvent();
var eventReceiver = new ReceivesEvent(eventSource);
eventSource.FireEvent();
}
}
I hope this helps you.
Working with events requires you to have both an event publisher and an event subscriber.
#chris' answer is correct.
Besides, you need to raise the event on the closest point where the action for which you want to be notified takes place.
For example, implementing the INotifyPropertyChanged interface.
public class Customer : INotifyPropertyChanged {
public string Name { get; set; }
public string Address {
get { return address; }
set {
address = value;
if (thereArePropertyChangedEventSubcribers())
raisePropertyChangedEventFor("Address");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void raisePropertyChangedEventFor(string propertyName) {
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
private bool thereArePropertyChangedEventSubcribers() {
return PropertyChanged != null;
}
private string address;
}
So here, the Customer class allows for the publishment of its change of address. So, whenever anyone is interested to be notified when the address has changed, it subscribes to the event like so:
Customer.PropertyChanged += new PropertyChangedEventHandler(customerPropertyChanged);
Or else like so:
Customer.PropertyChanged += customerPropertyChanged;
You might even have noticed that the closest point where the address has changed in directly after it has actually changed. The only requirement is that the method used as the event handler has the same signature as the event itself. If you take a look at the PropertyChangedEventHandler Delegate, one may notice that it signature awaits an object as the first parameter, that is, the object that fired the event, and a PropertyChangedEventArgs instance to notify about the property that has changed.
To come back to your example, you wish to be noticed whenever a log has been inserted into the underlying database so that a refresh of your Log window may occur. There are two questions that need to be answered whenever you want to use events.
What shall my publisher be?
What shall my subscriber be?
What shall my publisher be?
Should the MdiParent have the public delegate void EventHandler();?
Short answer: No!
If not where?
The event declaration best fits the publisher. Should you have a class responsible for logging, then this is where the public delegate void EventHandler(); should reside, as it is it that is responsible to raise the event whenever there are subscribers.
Whenever there is a successful Log inserted, it shall notify whatever subscriber interested to know about the new Log Entry.
public class Log {
public void UpdateLog(string description) {
// insert the new Log line into your database.
if (thereIsAtLeastOneNewLogEntryAddedSubscriber())
raiseTheNewLogEntryAddedEvent();
}
public event EventHandler NewLogEntryAdded;
private raiseTheNewLogEntryAddedEvent() {
NewLogEntryAdded(this, EventArgs.Empty);
}
private bool thereIsAtLeastOneNewLogEntryAddedSubscriber() {
return NewLogEntryAdded != null;
}
}
What shall my subscriber be?
This question can be answered through another question:
What do you need to do when the event fires?
In your case, you wish to update a Log window whenever it is opened.
The only bit I'm reasonably sure about is that the Window that displays the log (which has a method called public void UpdateLogDataGridView() - which calls the database object/methods to (re-)populate the datagridview) needs to have:
something like logGoneStale += new EventHandler(UpdateLogDataGridView); in it. Is that at least right?
Yes, you're right! =D
You actually subscribe to the event per this line. So, it tells the application that the window that displays the log is interested to know about log changes in your database.
public class WindowThatDisplaysTheLog : Form {
public WindowThatDisplaysTheLog() {
InitializeComponent();
log = new Log();
log.NewLogEntryAdded += UpdateLogDataGridView;
}
private void UpdateLogDataGridView(object sender, EventArgs e) {
// Reload your Log entries from the underlying database.
// You now shall see the LogDataGridView updating itself
// whenever a new log entry is inserted.
}
private Log log;
}
What are the differences between delegates and an events? Don't both hold references to functions that can be executed?
An Event declaration adds a layer of abstraction and protection on the delegate instance. This protection prevents clients of the delegate from resetting the delegate and its invocation list and only allows adding or removing targets from the invocation list.
To understand the differences you can look at this 2 examples
Example with Delegates (in this case, an Action - that is a kind of delegate that doesn't return a value)
public class Animal
{
public Action Run {get; set;}
public void RaiseEvent()
{
if (Run != null)
{
Run();
}
}
}
To use the delegate, you should do something like this:
Animal animal= new Animal();
animal.Run += () => Console.WriteLine("I'm running");
animal.Run += () => Console.WriteLine("I'm still running") ;
animal.RaiseEvent();
This code works well but you could have some weak spots.
For example, if I write this:
animal.Run += () => Console.WriteLine("I'm running");
animal.Run += () => Console.WriteLine("I'm still running");
animal.Run = () => Console.WriteLine("I'm sleeping") ;
with the last line of code, I have overridden the previous behaviors just with one missing + (I have used = instead of +=)
Another weak spot is that every class which uses your Animal class can invoke the delegate directly. For example, animal.Run() or animal.Run.Invoke() are valid outside the Animal class.
To avoid these weak spots you can use events in c#.
Your Animal class will change in this way:
public class ArgsSpecial : EventArgs
{
public ArgsSpecial (string val)
{
Operation=val;
}
public string Operation {get; set;}
}
public class Animal
{
// Empty delegate. In this way you are sure that value is always != null
// because no one outside of the class can change it.
public event EventHandler<ArgsSpecial> Run = delegate{}
public void RaiseEvent()
{
Run(this, new ArgsSpecial("Run faster"));
}
}
to call events
Animal animal= new Animal();
animal.Run += (sender, e) => Console.WriteLine("I'm running. My value is {0}", e.Operation);
animal.RaiseEvent();
Differences:
You aren't using a public property but a public field (using events, the compiler protects your fields from unwanted access)
Events can't be assigned directly. In this case, it won't give rise to the previous error that I have showed with overriding the behavior.
No one outside of your class can raise or invoke the event. For example, animal.Run() or animal.Run.Invoke() are invalid outside the Animal class and will produce compiler errors.
Events can be included in an interface declaration, whereas a field cannot
Notes:
EventHandler is declared as the following delegate:
public delegate void EventHandler (object sender, EventArgs e)
it takes a sender (of Object type) and event arguments. The sender is null if it comes from static methods.
This example, which uses EventHandler<ArgsSpecial>, can also be written using EventHandler instead.
Refer here for documentation about EventHandler
In addition to the syntactic and operational properties, there's also a semantical difference.
Delegates are, conceptually, function templates; that is, they express a contract a function must adhere to in order to be considered of the "type" of the delegate.
Events represent ... well, events. They are intended to alert someone when something happens and yes, they adhere to a delegate definition but they're not the same thing.
Even if they were exactly the same thing (syntactically and in the IL code) there will still remain the semantical difference. In general I prefer to have two different names for two different concepts, even if they are implemented in the same way (which doesn't mean I like to have the same code twice).
Here is another good link to refer to.
http://csharpindepth.com/Articles/Chapter2/Events.aspx
Briefly, the take away from the article - Events are encapsulation over delegates.
Quote from article:
Suppose events didn't exist as a concept in C#/.NET. How would another class subscribe to an event? Three options:
A public delegate variable
A delegate variable backed by a property
A delegate variable with AddXXXHandler and RemoveXXXHandler methods
Option 1 is clearly horrible, for all the normal reasons we abhor public variables.
Option 2 is slightly better, but allows subscribers to effectively override each other - it would be all too easy to write someInstance.MyEvent = eventHandler; which would replace any existing event handlers rather than adding a new one. In addition, you still need to write the properties.
Option 3 is basically what events give you, but with a guaranteed convention (generated by the compiler and backed by extra flags in the IL) and a "free" implementation if you're happy with the semantics that field-like events give you. Subscribing to and unsubscribing from events is encapsulated without allowing arbitrary access to the list of event handlers, and languages can make things simpler by providing syntax for both declaration and subscription.
What a great misunderstanding between events and delegates!!! A delegate specifies a TYPE (such as a class, or an interface does), whereas an event is just a kind of MEMBER (such as fields, properties, etc). And, just like any other kind of member an event also has a type. Yet, in the case of an event, the type of the event must be specified by a delegate. For instance, you CANNOT declare an event of a type defined by an interface.
Concluding, we can make the following Observation: the type of an event MUST be defined by a delegate. This is the main relation between an event and a delegate and is described in the section II.18 Defining events of ECMA-335 (CLI) Partitions I to VI:
In typical usage, the TypeSpec (if present) identifies a delegate whose signature matches the arguments passed to the event’s fire method.
However, this fact does NOT imply that an event uses a backing delegate field. In truth, an event may use a backing field of any different data structure type of your choice. If you implement an event explicitly in C#, you are free to choose the way you store the event handlers (note that event handlers are instances of the type of the event, which in turn is mandatorily a delegate type---from the previous Observation). But, you can store those event handlers (which are delegate instances) in a data structure such as a List or a Dictionary or any other else, or even in a backing delegate field. But don’t forget that it is NOT mandatory that you use a delegate field.
NOTE: If you have access to C# 5.0 Unleashed, read the "Limitations on Plain Use of Delegates" in Chapter 18 titled "Events" to understand better the differences between the two.
It always helps me to have a simple, concrete example. So here's one for the community. First I show how you can use delegates alone to do what Events do for us. Then I show how the same solution would work with an instance of EventHandler. And then I explain why we DON'T want to do what I explain in the first example. This post was inspired by an article by John Skeet.
Example 1: Using public delegate
Suppose I have a WinForms app with a single drop-down box. The drop-down is bound to an List<Person>. Where Person has properties of Id, Name, NickName, HairColor. On the main form is a custom user control that shows the properties of that person. When someone selects a person in the drop-down the labels in the user control update to show the properties of the person selected.
Here is how that works. We have three files that help us put this together:
Mediator.cs -- static class holds the delegates
Form1.cs -- main form
DetailView.cs -- user control shows all details
Here is the relevant code for each of the classes:
class Mediator
{
public delegate void PersonChangedDelegate(Person p); //delegate type definition
public static PersonChangedDelegate PersonChangedDel; //delegate instance. Detail view will "subscribe" to this.
public static void OnPersonChanged(Person p) //Form1 will call this when the drop-down changes.
{
if (PersonChangedDel != null)
{
PersonChangedDel(p);
}
}
}
Here is our user control:
public partial class DetailView : UserControl
{
public DetailView()
{
InitializeComponent();
Mediator.PersonChangedDel += DetailView_PersonChanged;
}
void DetailView_PersonChanged(Person p)
{
BindData(p);
}
public void BindData(Person p)
{
lblPersonHairColor.Text = p.HairColor;
lblPersonId.Text = p.IdPerson.ToString();
lblPersonName.Text = p.Name;
lblPersonNickName.Text = p.NickName;
}
}
Finally we have the following code in our Form1.cs. Here we are Calling OnPersonChanged, which calls any code subscribed to the delegate.
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
Mediator.OnPersonChanged((Person)comboBox1.SelectedItem); //Call the mediator's OnPersonChanged method. This will in turn call all the methods assigned (i.e. subscribed to) to the delegate -- in this case `DetailView_PersonChanged`.
}
Ok. So that's how you would get this working without using events and just using delegates. We just put a public delegate into a class -- you can make it static or a singleton, or whatever. Great.
BUT, BUT, BUT, we do not want to do what I just described above. Because public fields are bad for many, many reason. So what are our options? As John Skeet describes, here are our options:
A public delegate variable (this is what we just did above. don't do this. i just told you above why it's bad)
Put the delegate into a property with a get/set (problem here is that subscribers could override each other -- so we could subscribe a bunch of methods to the delegate and then we could accidentally say PersonChangedDel = null, wiping out all of the other subscriptions. The other problem that remains here is that since the users have access to the delegate, they can invoke the targets in the invocation list -- we don't want external users having access to when to raise our events.
A delegate variable with AddXXXHandler and RemoveXXXHandler methods
This third option is essentially what an event gives us. When we declare an EventHandler, it gives us access to a delegate -- not publicly, not as a property, but as this thing we call an event that has just add/remove accessors.
Let's see what the same program looks like, but now using an Event instead of the public delegate (I've also changed our Mediator to a singleton):
Example 2: With EventHandler instead of a public delegate
Mediator:
class Mediator
{
private static readonly Mediator _Instance = new Mediator();
private Mediator() { }
public static Mediator GetInstance()
{
return _Instance;
}
public event EventHandler<PersonChangedEventArgs> PersonChanged; //this is just a property we expose to add items to the delegate.
public void OnPersonChanged(object sender, Person p)
{
var personChangedDelegate = PersonChanged as EventHandler<PersonChangedEventArgs>;
if (personChangedDelegate != null)
{
personChangedDelegate(sender, new PersonChangedEventArgs() { Person = p });
}
}
}
Notice that if you F12 on the EventHandler, it will show you the definition is just a generic-ified delegate with the extra "sender" object:
public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e);
The User Control:
public partial class DetailView : UserControl
{
public DetailView()
{
InitializeComponent();
Mediator.GetInstance().PersonChanged += DetailView_PersonChanged;
}
void DetailView_PersonChanged(object sender, PersonChangedEventArgs e)
{
BindData(e.Person);
}
public void BindData(Person p)
{
lblPersonHairColor.Text = p.HairColor;
lblPersonId.Text = p.IdPerson.ToString();
lblPersonName.Text = p.Name;
lblPersonNickName.Text = p.NickName;
}
}
Finally, here's the Form1.cs code:
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
Mediator.GetInstance().OnPersonChanged(this, (Person)comboBox1.SelectedItem);
}
Because the EventHandler wants and EventArgs as a parameter, I created this class with just a single property in it:
class PersonChangedEventArgs
{
public Person Person { get; set; }
}
Hopefully that shows you a bit about why we have events and how they are different -- but functionally the same -- as delegates.
You can also use events in interface declarations, not so for delegates.
Delegate is a type-safe function pointer. Event is an implementation of publisher-subscriber design pattern using delegate.
An event in .net is a designated combination of an Add method and a Remove method, both of which expect some particular type of delegate. Both C# and vb.net can auto-generate code for the add and remove methods which will define a delegate to hold the event subscriptions, and add/remove the passed in delegagte to/from that subscription delegate. VB.net will also auto-generate code (with the RaiseEvent statement) to invoke the subscription list if and only if it is non-empty; for some reason, C# doesn't generate the latter.
Note that while it is common to manage event subscriptions using a multicast delegate, that is not the only means of doing so. From a public perspective, a would-be event subscriber needs to know how to let an object know it wants to receive events, but it does not need to know what mechanism the publisher will use to raise the events. Note also that while whoever defined the event data structure in .net apparently thought there should be a public means of raising them, neither C# nor vb.net makes use of that feature.
To define about event in simple way:
Event is a REFERENCE to a delegate with two restrictions
Cannot be invoked directly
Cannot be assigned values directly (e.g eventObj = delegateMethod)
Above two are the weak points for delegates and it is addressed in event. Complete code sample to show the difference in fiddler is here https://dotnetfiddle.net/5iR3fB .
Toggle the comment between Event and Delegate and client code that invokes/assign values to delegate to understand the difference
Here is the inline code.
/*
This is working program in Visual Studio. It is not running in fiddler because of infinite loop in code.
This code demonstrates the difference between event and delegate
Event is an delegate reference with two restrictions for increased protection
1. Cannot be invoked directly
2. Cannot assign value to delegate reference directly
Toggle between Event vs Delegate in the code by commenting/un commenting the relevant lines
*/
public class RoomTemperatureController
{
private int _roomTemperature = 25;//Default/Starting room Temperature
private bool _isAirConditionTurnedOn = false;//Default AC is Off
private bool _isHeatTurnedOn = false;//Default Heat is Off
private bool _tempSimulator = false;
public delegate void OnRoomTemperatureChange(int roomTemperature); //OnRoomTemperatureChange is a type of Delegate (Check next line for proof)
// public OnRoomTemperatureChange WhenRoomTemperatureChange;// { get; set; }//Exposing the delegate to outside world, cannot directly expose the delegate (line above),
public event OnRoomTemperatureChange WhenRoomTemperatureChange;// { get; set; }//Exposing the delegate to outside world, cannot directly expose the delegate (line above),
public RoomTemperatureController()
{
WhenRoomTemperatureChange += InternalRoomTemperatuerHandler;
}
private void InternalRoomTemperatuerHandler(int roomTemp)
{
System.Console.WriteLine("Internal Room Temperature Handler - Mandatory to handle/ Should not be removed by external consumer of ths class: Note, if it is delegate this can be removed, if event cannot be removed");
}
//User cannot directly asign values to delegate (e.g. roomTempControllerObj.OnRoomTemperatureChange = delegateMethod (System will throw error)
public bool TurnRoomTeperatureSimulator
{
set
{
_tempSimulator = value;
if (value)
{
SimulateRoomTemperature(); //Turn on Simulator
}
}
get { return _tempSimulator; }
}
public void TurnAirCondition(bool val)
{
_isAirConditionTurnedOn = val;
_isHeatTurnedOn = !val;//Binary switch If Heat is ON - AC will turned off automatically (binary)
System.Console.WriteLine("Aircondition :" + _isAirConditionTurnedOn);
System.Console.WriteLine("Heat :" + _isHeatTurnedOn);
}
public void TurnHeat(bool val)
{
_isHeatTurnedOn = val;
_isAirConditionTurnedOn = !val;//Binary switch If Heat is ON - AC will turned off automatically (binary)
System.Console.WriteLine("Aircondition :" + _isAirConditionTurnedOn);
System.Console.WriteLine("Heat :" + _isHeatTurnedOn);
}
public async void SimulateRoomTemperature()
{
while (_tempSimulator)
{
if (_isAirConditionTurnedOn)
_roomTemperature--;//Decrease Room Temperature if AC is turned On
if (_isHeatTurnedOn)
_roomTemperature++;//Decrease Room Temperature if AC is turned On
System.Console.WriteLine("Temperature :" + _roomTemperature);
if (WhenRoomTemperatureChange != null)
WhenRoomTemperatureChange(_roomTemperature);
System.Threading.Thread.Sleep(500);//Every second Temperature changes based on AC/Heat Status
}
}
}
public class MySweetHome
{
RoomTemperatureController roomController = null;
public MySweetHome()
{
roomController = new RoomTemperatureController();
roomController.WhenRoomTemperatureChange += TurnHeatOrACBasedOnTemp;
//roomController.WhenRoomTemperatureChange = null; //Setting NULL to delegate reference is possible where as for Event it is not possible.
//roomController.WhenRoomTemperatureChange.DynamicInvoke();//Dynamic Invoke is possible for Delgate and not possible with Event
roomController.SimulateRoomTemperature();
System.Threading.Thread.Sleep(5000);
roomController.TurnAirCondition (true);
roomController.TurnRoomTeperatureSimulator = true;
}
public void TurnHeatOrACBasedOnTemp(int temp)
{
if (temp >= 30)
roomController.TurnAirCondition(true);
if (temp <= 15)
roomController.TurnHeat(true);
}
public static void Main(string []args)
{
MySweetHome home = new MySweetHome();
}
}
For people live in 2020, and want a clean answer...
Definitions:
delegate: defines a function pointer.
event: defines
(1) protected interfaces, and
(2) operations(+=, -=), and
(3) advantage: you don't need to use new keyword anymore.
Regarding the adjective protected:
// eventTest.SomeoneSay = null; // Compile Error.
// eventTest.SomeoneSay = new Say(SayHello); // Compile Error.
Also notice this section from Microsoft: https://learn.microsoft.com/en-us/dotnet/standard/events/#raising-multiple-events
Code Example:
with delegate:
public class DelegateTest
{
public delegate void Say(); // Define a pointer type "void <- ()" named "Say".
private Say say;
public DelegateTest() {
say = new Say(SayHello); // Setup the field, Say say, first.
say += new Say(SayGoodBye);
say.Invoke();
}
public void SayHello() { /* display "Hello World!" to your GUI. */ }
public void SayGoodBye() { /* display "Good bye!" to your GUI. */ }
}
with event:
public class EventTest
{
public delegate void Say();
public event Say SomeoneSay; // Use the type "Say" to define event, an
// auto-setup-everything-good field for you.
public EventTest() {
SomeoneSay += SayHello;
SomeoneSay += SayGoodBye;
SomeoneSay();
}
public void SayHello() { /* display "Hello World!" to your GUI. */ }
public void SayGoodBye() { /* display "Good bye!" to your GUI. */ }
}
Reference:
Event vs. Delegate - Explaining the important differences between the Event and Delegate patterns in C# and why they're useful.: https://dzone.com/articles/event-vs-delegate
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.