JadziaMD
JadziaMD

Reputation: 2750

Pattern for Raising Events

I have an abstract class A which has a required function for checking thresholds. When a threshold is violated I want an event raised that says notify me. I've done this sort of thing in Qt many times, but I can't seem to figure out how to transfer this to C#. Here's the structure I've currently got in mind.

namespace N
{
  abstract class A
  {
    public delegate void Notify();
    public event Notify Notifier;
    public abstract void CheckThreshold();
  }

  class B : A
  {
    public override void CheckThreshold()
    {
       Notifier();
    }
  }

  class N
  {
    public AlertMe()
    {
    }
    public static Main()
    {
      var b = new B();
      b.Notifier += new A.Notify(AlertMe);

      b.CheckThreshold();
    }
  }
}

Upvotes: 2

Views: 612

Answers (5)

plinth
plinth

Reputation: 49179

Typically the form you want to follow is this:

public event EventHandler<SomeEventArgs> SomeEvent = (s, e) => { };

protected virtual void OnSomeEvent(SomeEventArgs e)
{
    SomeEvent(this, e);
}

so in your case you probably want:

abstract class A {

    public event EventHandler<EventArgs> ThresholdExceeded = (s, e) => { };

    protected virtual void OnThresholdExceeded(EventArgs e)
    {
        ThresholdExceeded(e);
    }

    public abstract void CheckThreshold();
}

class B : A {
    public override void CheckThreshold()
    {
        if (/* your condition */) OnThresholdExceeded(new EventArgs());
    }
}

Now a few things - the EventHandler type is some nice syntactic sugar for making an event of a particular type. The lambda expression on the right initializes it to a default handler so you don't have to check it for null before you invoke it.

EventArgs is event-specific information - you have none, but if you did you would subclass EventArgs and put in whatever data your event receivers would need.

The pattern of public event SomeEventName and protected virtual void OnSomeEvent pair is prescribed by Microsoft for events in .NET. You don't have to follow this, but it's what .NET programmers want.

Upvotes: 2

Sergey Teplyakov
Sergey Teplyakov

Reputation: 11647

There is several issues with this code.

First of all you should use EventHandler built-in delegate for defining events. Second, you can't raise an event outside the class that defines it (that's why you can't use your Notify() from the descendants). Third, you can use Template Method Design Pattern and define contract between your base class and it descendants more clearly and implement one part of the threashold check.

And finally I don't understand at all why you need inheritance hierarchy at all? Maybe you can implement all required logic in one class? But anyway here code that would compile and behave correctly:

  abstract class A
  {
    // Avoid defining custom delegate at all because there is a lot of 
    // build-in events for every case, like EventHandler<T>, 
    // Func<T>, Action<T> etc
    // public delegate void Notify();
    public event EventHandler ThreasholdViolated;

    protected void OnThreasholdViolated()
    {
       var handler = ThreasholdViolated;
       if (handler != null)
         handler(this, EventArgs.Empty);
    }

    public abstract void CheckThreshold();
  }

  class B : A
  {
    public override void CheckThreshold()
    {
       OnThreasholdViolated();
    }
  }

Upvotes: 1

fsimonazzi
fsimonazzi

Reputation: 3013

The usual pattern is to provide a protected virtual method in the base class as shown in http://msdn.microsoft.com/en-us/library/vstudio/9aackb16(v=vs.100).aspx. The convention for the name for that method is On[EventName] and takes the event args instance.

Also follow the convention of using EventHandler or EventHandler for the delegate, and provide both the event originator and the corresponding arguments. You can find more about this in http://msdn.microsoft.com/en-us/library/vstudio/ms229011(v=vs.100).aspx. Note that the sample from MSDN does not follow all these conventions.

Upvotes: 0

Chris Doggett
Chris Doggett

Reputation: 20757

public abstract class A
{
    public EventHandler<EventArgs> OnThresholdViolated;

    public abstract void CheckThreshold();
}

public class B : A
{
    public B(EventHandler<EventArgs> alertMe) {
        OnThresholdViolated += alertMe;
    }

    public override void CheckThreshold()
    {
        if (null != OnThresholdViolated)
        {
            OnThresholdViolated(this, EventArgs.Empty);
        }
    }
}

Then call using:

        B b = new B(AlertMe);

        b.CheckThreshold();

Upvotes: -1

vigoo
vigoo

Reputation: 311

You could define a helper method in base class A

protected void FireNotification() 
{
    if (Notifier != null)
        Notifier();
}

and call this from the overridden CheckTreshold.

Upvotes: 1

Related Questions