To start with, those are not events. And this is not how events and work and not how event data is passed. Please see my comments to the question.
I would quickly send you to the reading of standard documentation on events. You need to learn this topic anyway. But you also need to do something which is not properly explained in MSDN, because this "something" is not formally required, be is a part of some conventions for the cultured code. Perhaps it would be better to show you some code sample.
First of all, event data should be passed using the class derived
from System.EventArgs
. This is not required formally but is required as the good style convention; in return, .NET give you valuable support by its .NET BCL types. Do this:
class Person { }
public class MyEventArgs : System.EventArgs {
internal MyEventArgs(Person person) { this.Person = person; }
public Person Person { get; private set; }
}
Now, let's add the class declaring an event instance. It can be your
Person
, but it's better to show more general case when this is a different class. First of all, if you used a "regular" delegate instance, not event instance, your delegate type matching the event delegate type could be based on the
System.Action
declaration. It could be
System.Action<object, MyEventArgs> myDelegateInstance;
But! This convention is not applied to "regular delegate instances", but only to delegate instances. But for delegate instances, .NET BCL gives you more , different support, so you don't even need this
Action
declaration. Instead, you should use
public class EventImplementor {
public event System.EventHandler<MyEventArgs> PersonChanged;
}
Now, the problem is: where to invoke the event? The trick is: it is only allowed to be done in the same class; any other code won't compile. This is a very important .NET
fool-proof feature.
So, you would need to add:
public class EventImplementor {
public event System.EventHandler<MyEventArgs> PersonChanged;
void InvokePersonChanged() {
if (PersonChanged != null)
PersonChanged.Invoke(this, new MyEventArgs(this.person));
}
Person Person {
get { return this.person; }
set {
if (value == this.person) return;
this.person = value;
InvokePersonChanged();
}
}
Person person;
}
Not it's time to address your
OnSomethingChanged
. The convention is: if you have the property
Person
, the method named like
OnPersonChanged
1) should be virtual, 2) only protected, 3) should invoke
PersonChanged
:
public class EventImplementor {
public event System.EventHandler<MyEventArgs> PersonChanged;
protected virtual void OnPersonChanged() {
if (PersonChanged != null)
PersonChanged.Invoke(this, new MyEventArgs(this.person));
}
}
Why? By a very serious reason. It give some extra flexibility for handling the change of the person. First way won't use the event, but will not allow for event multi-casting. It's faster:
class MyDerivedClass : EventImplementor {
protected override void OnPersonChanged() {
}
}
Another way is handling the event; as I made event public (could be internal), it can be done in any place of code, even in a different assembly:
EventImplementor implementor = new EventImplementor();
implementor.PersonChanged += (sender, eventArgs) => {
EventImplementor implementorSender = (EventImplementor)sender;
Person person = eventArgs.Person;
};
Are you getting the idea?
[EDIT #1]
I apparently pretty much ignore the fact that you are changing some hash, not person. This if, first of all, because I wanted to make my tutorial as simple as possible. The difference is very little. Instead of having
MyEventArgs.Person
, you could have two: one property for person, another for hash object. Also, you should rather add more events, such as
PersonAdding
,
PersonAdded
,
PersonRemoving
, PersonRemoved. If this is not clear, please ask me the question.
[EDIT #2]
Some weird members of this site don't accept
anonymous methods. I think this is a big mistake, but for completeness:
static void PersonHandler(object sender, MyEventArgs eventArg) { }
implementor.PersonChanged += PersonHandler;
For C#.v2, type inference cannot be used even for the anonymous. You would need:
implementor.PersonChanged += delegate(object sender, MyEventArgs) => {
}
Several handlers can be added to the invocation list of each event handler; they all will be invoked through one invocation call.
—SA