This is the standard delegate signature for event handlers.
The .NET Framework guidelines indicate that the delegate type used for an event should take two parameters, an "object source" parameter indicating the source of the event, and an "e" parameter that encapsulates any additional information about the event. The type of the "e" parameter should derive from the EventArgs
class. For events that do not use any additional information, the .NET Framework has already defined an appropriate delegate type: EventHandler
.
The
sender
parameter is the instance of the object which raised the event. The code for the class which raises the event is responsible for passing the correct object to the handler. In the case of
static
events, this parameter will be
null
.
The
e
parameter is either an instance of the
EventArgs
class, if the event has no additional data to pass; or an instance of a class derived from
EventArgs
, which will contain the data associated with the event. Again, the class which raises the event is responsible for creating and populating this argument.
This signature is only a recommendation. There is nothing to prevent a class from defining an event with a completely different signature. However, most classes abide by the framework guidelines, and it's strongly recommended that your own classes do so as well.
The main benefit of this syntax is that handlers don't have to change if the sender class decides to add new data to the event. If the data was simply passed as arguments to the handler, this would not work.
For example:
public class Source
{
public delegate void FooEvent();
public event FooEvent Foo;
public void Bar()
{
FooEvent handler = Foo;
if (handler != null) handler();
}
}
public class Subscriber
{
public Subscriber(Source source)
{
source.Foo += Source_OnFoo;
}
private void Source_OnFoo()
{
...
}
}
public class Source
{
public delegate void FooEvent(int answer);
public event FooEvent Foo;
public void Bar()
{
FooEvent handler = Foo;
if (handler != null) handler(42);
}
}
public class Subscriber
{
public Subscriber(Source source)
{
source.Foo += Source_OnFoo;
}
private void Source_OnFoo()
{
...
}
}
When you follow the guidelines, this isn't a problem:
public class Source
{
public event EventHandler Foo;
public void Bar()
{
EventHandler handler = Foo;
if (handler != null) handler(this, EventArgs.Empty);
}
}
public class Subscriber
{
public Subscriber(Source source)
{
source.Foo += Source_OnFoo;
}
private void Source_OnFoo(object sender, EventArgs e)
{
...
}
}
public class FooEventArgs : EventArgs
{
public FooEventArgs(int answer)
{
Answer = answer;
}
public int Answer { get; private set; }
}
public class Source
{
public event EventHandler<FooEventArgs> Foo;
public void Bar()
{
EventHandler<FooEventArgs> handler = Foo;
if (handler != null) handler(this, new FooEventArgs(42));
}
}
public class Subscriber
{
public Subscriber(Source source)
{
source.Foo += Source_OnFoo;
}
private void Source_OnFoo(object sender, EventArgs e)
{
...
}
}