Thursday, December 20, 2007
Derived classes and events
Events are a useful feature of the C# language and allow for clients to be notified when the state of a server changes. You create an event by declaring it in the class that will raise the event:
Here, I used the generic event template to eliminate the need to define a separate delegate. To register a callback method with the event, we do the following in the class that will receive the event notification from the class that raised the event:
When the event is raised the message_NotifyClient method will execute. To raise the event we add the following to the class that raises the event:
Here, we make a copy of the event since access to the event is not thread-safe (i.e. another thread could delete/modify the event before the if (handler != null) completes). When the client wants to raise the event, it does so by executing the OnNotifyClient method:
When OnNotifyClient is executed, the message_NotifyClient method is executed.
Derived classes and events
An event can only be raised from methods declare within the class that declared the event. So events declared in class A can only be raised from methods within class A. By default, events are not inherited by derived classes, so in the following base class definition:
with the derived class definition
The derived class will not have access to the NotifyClient event since the NotifyClient event was not declared in the Derived class. There are two ways to workaround this requirement:
The second approach is to declare the event virtual in the Base class, then override the event in the Derived class:
Which approach you take is up to you. Both approaches give the Derived class the flexibility to perform Derived-specific tasks around the decision to raise the event. It really comes down to which approach is preferred.
public event EventHandlerNotifyClient;
Here, I used the generic event template to eliminate the need to define a separate delegate. To register a callback method with the event, we do the following in the class that will receive the event notification from the class that raised the event:
message.NotifyClient += new EventHandler(message_NotifyClient);
static void message_NotifyClient(object sender, EventArgs e)
{
throw new Exception("The method or operation is not implemented.");
}
When the event is raised the message_NotifyClient method will execute. To raise the event we add the following to the class that raises the event:
protected virtual void OnNotifyClient(EventArgs e)
{
EventHandlerhandler = NotifyClient;
if (handler != null)
handler(this, e);
}
Here, we make a copy of the event since access to the event is not thread-safe (i.e. another thread could delete/modify the event before the if (handler != null) completes). When the client wants to raise the event, it does so by executing the OnNotifyClient method:
private void DoSomething()
{
// Do something...
OnNotifyClient(new EventArgs());
}
When OnNotifyClient is executed, the message_NotifyClient method is executed.
Derived classes and events
An event can only be raised from methods declare within the class that declared the event. So events declared in class A can only be raised from methods within class A. By default, events are not inherited by derived classes, so in the following base class definition:
public class Base
{
public event EventHanderNotifyClient;
}
with the derived class definition
public class Derived : Base
{
private void DoSomething()
{
EventHandlerhandler = NotifyClient;
if (handler != null)
handler(this, new EventArgs());
}
}
The derived class will not have access to the NotifyClient event since the NotifyClient event was not declared in the Derived class. There are two ways to workaround this requirement:
- Define the OnNotifyClient method in the Base class as virtual and then override the OnNotifyClient method in the Derived class
- Declare the event as virtual in the Base class, then override the event in the Derived class
protected override void OnNotifyClient(EventArgs e)
{
EventHandlerhandler = NotifyClient;
if (handler != null)
handler(this, e);
}
protected void DoSomething()
{
// Do something Derived-class specific, then call OnNotifyClient
OnNotifyClient(new EventArgs());
}
The second approach is to declare the event virtual in the Base class, then override the event in the Derived class:
public class Base
{
public virtual event EventHandlerNotifyClient;
...
}
public class Derived : Base
{
public override event EventHandlerNotifyClient;
public void DoSomething()
{
EventHandlerhandler = NotifyClient;
// Here, we can access the NotifyClient directly since we've overridden access
if (handler != null)
handler(this, new EventArgs());
}
}
Which approach you take is up to you. Both approaches give the Derived class the flexibility to perform Derived-specific tasks around the decision to raise the event. It really comes down to which approach is preferred.