views:

46

answers:

3

I am trying to create what I am thinking of as a translation class, so that my program can speak to a variety of target platforms. Each platform will be handled by a separate implementation of an abstract class. I have pared things down for the sake of simplicity.

I have an abstract class, with a couple of abstract methods:

abstract class ControllerBase
{
    public abstract bool EnableDTMFDetection(string CallID, Party Party);
    public abstract bool DisableDTMFDetection(string CallID, Party Party);
}

Subsequently a class (classes) which derive from ControllerBase, and fully implement those methods:

class PlatformOne : ControllerBase
{
    public override bool EnableDTMFDetection(string CallID, Party Party)
    {
        // Do Stuff
        return true;
    }

    public override bool DisableDTMFDetection(string CallID, Party Party)
    {
        // Do Stuff
        return true;
    }
}

So far so good. For PlatformOne I am forced to define each of those methods, prescribing how I will send an outgoing message to my target platform.

It is the incoming events that have got me. I need to be able to raise events from within my derived classes. When I add the following to controllerbase:

    public delegate void MyEventHandler(object sender, EventArgs e);
    public event MyEventHandler MyEvent;

It compiles fine, but I can't raise the event from within my derived class without the error: "The event 'ControllerBase.MyEvent' can only appear on the left hand side of += or -= (except when used from within the type 'ControllerBase')"

So, a) How do I raise my event from within my derived class, and b) can anyone suggest a mechanism for enforcing the wiring up of specified events from within my derived class (a la abstract functions or interface methods). Thank you call :)

+4  A: 

The simplest way of doing this is to write a method in your base class to raise it:

protected void OnMyEvent(EventArgs e)
{
    // Note the copy to a local variable, so that we don't risk a
    // NullReferenceException if another thread unsubscribes between the test and
    // the invocation.
    EventHandler handler = MyEvent;
    if (handler != null)
    {
        handler(this, e);
    }
}

You may want to make it a virtual method so you can override it in derived classes... it depends on your use case.

Note that this isn't forcing an implementation of anything in the derived class - but I think it's what you actually want.

Jon Skeet
Jon - thank you for the answer - in the your example, where and how are you suggesting I create the MyEvent instance of EventHander?
Adrian Hand
@Adrian: You can just declared it as a field-like event in the base class, as you've shown near the bottom of your question.
Jon Skeet
Jon - I believe I have things working now, and I thank you very much. Two questions remain: When done exactly as described, I need to do say "var handler = MyEvent;" as opposed to "EventHandler handler = My Event;", and secondly I am flat out failing to understand why I can't do this in my derived class - basically an explanation for my initial "The event 'ControllerBase.MyEvent' can only appear on the left hand side of += or -=" error.
Adrian Hand
@Adrian: I hadn't noticed that you weren't using the standard `EventHandler` type. You can adapt my code to just declare the variable as type `MyEventHandler` instead. As for using the event in a derived class: read http://csharpindepth.com/Articles/Chapter2/Events.aspx
Jon Skeet
@Jon - thank you again, that link contained exactly what I was looking for from the beginning - I daresay I need to enhance my google-fu as well as my eventing knowledge!
Adrian Hand
+1  A: 

Create a protected event invocator in the abstract class.

protected void InvokeMyEvent(EventArgs args)
{
    var handler = MyEvent;
    if (hander != null)
        handler(this, args);
}
Kaiser Soze
+1  A: 

The standard pattern is to add an On<EventName> virtual protected method to raise an event

protected virtual OnMyEvent(EventArgs e) {
    var h = MyEvent;
    if (h != null)
        h(this, e);
}

Also bear in mind that events can be made abstract or virtual:

public abstract event MyEventHandler MyEvent;

although this is only generally used in interfaces, which might be better for your ControllerBase depending on your exact requirements:

public interface IController {
    event MyEventHandler MyEvent;
    bool EnableDTMFDetection(string CallID, Party Party);
    bool DisableDTMFDetection(string CallID, Party Party);
}

public PlatformOne : IControllerBase

    // yadda yadda...

    public event MyEventHandler MyEvent;

    // members of PlatformOne can invoke MyEvent as a normal delegate
}
thecoop