153

I have a base class that contains the following events:

public event EventHandler Loading;
public event EventHandler Finished;

In a class that inherits from this base class I try to raise the event:

this.Loading(this, new EventHandler()); // All we care about is which object is loading.

I receive the following error:

The event 'BaseClass.Loading' can only appear on the left hand side of += or -= (BaseClass')

I am assuming I cannot access these events the same as other inherited members?

jwarzech
  • 6,596
  • 11
  • 52
  • 72
  • This question was already answered by [Frederik Gheysels](https://stackoverflow.com/users/55774/frederik-gheysels). The same practice is recommended on Microsoft Docs: [How to raise base class events in derived classes (C# Programming Guide)](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/events/how-to-raise-base-class-events-in-derived-classes) as an official "C# Programming Guide" – Eliahu Aaron May 25 '20 at 15:06

5 Answers5

171

What you have to do , is this:

In your base class (where you have declared the events), create protected methods which can be used to raise the events:

public class MyClass
{
   public event EventHandler Loading;
   public event EventHandler Finished;

   protected virtual void OnLoading(EventArgs e)
   {
       EventHandler handler = Loading;
       if( handler != null )
       {
           handler(this, e);
       }
   }

   protected virtual void OnFinished(EventArgs e)
   {
       EventHandler handler = Finished;
       if( handler != null )
       {
           handler(this, e);
       }
   }
}

(Note that you should probably change those methods, in order to check whether you have to Invoke the eventhandler or not).

Then, in classes that inherit from this base class, you can just call the OnFinished or OnLoading methods to raise the events:

public AnotherClass : MyClass
{
    public void DoSomeStuff()
    {
        ...
        OnLoading(EventArgs.Empty);
        ...
        OnFinished(EventArgs.Empty);
    }
}
Frederik Gheysels
  • 56,135
  • 11
  • 101
  • 154
  • 5
    Those methods should be protected virtual unless there's some reason to do otherwise. – Max Schmeling Apr 16 '09 at 14:07
  • 6
    Why should it be virtual ? I would declare it virtual if I wanted inheritors to change the way the event should be raised, but most of the time, I see no reason to do this ... – Frederik Gheysels Apr 16 '09 at 14:12
  • By guidelines Microsoft says it should be virtual so that inheritants can control the event.. additionally the On protected method should take event args, not create them itself. This answer is wrong compared to the correct one by Adam Robinson. – meandmycode Apr 16 '09 at 14:15
  • @Frederik: The convention for inheritors handling events is to override the raising event rather than attaching it themselves, as a) polymorphism is (slightly) more efficient than a multicast delegate, and b) it gives them control over when their code is executed (ie before or after subscriber code) – Adam Robinson Apr 16 '09 at 14:15
  • 4
    Official guidelines: http://msdn.microsoft.com/en-us/library/w369ty8x(VS.80).aspx – meandmycode Apr 16 '09 at 14:17
  • meandmycode: regarding the arguments: this is just some example code. Offcourse it is better to pass them as arguments ... I'll change it if it makes you happy. :o: – Frederik Gheysels Apr 16 '09 at 14:26
  • 5
    Regarding making the method virtual, so that inheritors can override the event invocation behaviour: How many times have you been in a situation where this was necessary ? Next to that; in the overriden method, you can't raise the event, since you'll get the same error as the one mentioned by TS. – Frederik Gheysels Apr 16 '09 at 14:31
  • Yes, you can raise it by calling the base implementation. But what other additional functionality could you possibly think of ? – Frederik Gheysels Apr 16 '09 at 14:34
  • 1
    @Frederik: As stated earlier, controlling whether YOUR code executes before or after the code of the event subscribers. I do this on a regular basis. – Adam Robinson Apr 16 '09 at 15:14
  • 2
    @Verax I follow it because the reasoning is sound, depending on how re-usable and extensible I expect the code to be, I provided official guidelines to back that up.. at the time of writing you also seem very new to .NET Verax so it is a little perplexing that you dug this up to disagree with my 7 years of experience – meandmycode Mar 01 '12 at 21:47
135

You can only access an event in the declaring class, as .NET creates private instance variables behind the scenes that actually hold the delegate. Doing this..

public event EventHandler MyPropertyChanged;

is actually doing this;

private EventHandler myPropertyChangedDelegate;

public event EventHandler MyPropertyChanged
{
    add { myPropertyChangedDelegate += value; }
    remove { myPropertyChangedDelegate -= value; }
}

and doing this...

MyPropertyChanged(this, EventArgs.Empty);

is actually this...

myPropertyChangedDelegate(this, EventArgs.Empty);

So you can (obviously) only access the private delegate instance variable from within the declaring class.

The convention is to provide something like this in the declaring class..

protected virtual void OnMyPropertyChanged(EventArgs e)
{
    EventHandler invoker = MyPropertyChanged;

    if(invoker != null) invoker(this, e);
}

You can then call OnMyPropertyChanged(EventArgs.Empty) from anywhere in that class or below the inheritance heirarchy to invoke the event.

Adam Robinson
  • 182,639
  • 35
  • 285
  • 343
8

I am assuming I cannot access these events the same as other inherited members?

Precisely. It's customary to provide a protected function OnXyz or RaiseXyz for each event in the base class to enable raising from inherited classes. For example:

public event EventHandler Loading;

protected virtual void OnLoading() {
    EventHandler handler = Loading;
    if (handler != null)
        handler(this, EventArgs.Empty);
}

Called in the inherited class:

OnLoading();
Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
0

You can try this way, It works for me:

public delegate void MyEventHaldler(object sender, EventArgs e);

public class B
{
    public virtual event MyEventHaldler MyEvent;
    protected override void OnChanged(EventArgs e)
    {
        if (MyEvent != null)
            MyEvent(this, e);
    }
}

public class D : B
{
    public override event MyEventHaldler MyEvent;
    protected override void OnChanged(EventArgs e)
    {
        if (MyEvent != null)
            MyEvent(this, e);
    }
}
  • 2
    Note that this article warns against declaring virtual events and overriding them as it claims the compiler doesn't handle this correctly: https://msdn.microsoft.com/en-us/library/hy3sefw3.aspx – public wireless Feb 13 '15 at 20:56
0

not to resurrect an old thread but in case anybody is looking, what I did was

protected EventHandler myPropertyChangedDelegate;

public event EventHandler MyPropertyChanged
{
    add { myPropertyChangedDelegate += value; }
    remove { myPropertyChangedDelegate -= value; }
}

This lets you inherit the event in a derived class so you can invoke it without requiring to wrap the method while keeping the += syntax. I guess you could still do that with the wrapping methods if you did

public event EventHandler MyPropertyChanged
{
   add { AddDelegate(value); }
   remove { RemoveDelegate(value); }
}
Zeraphil
  • 1
  • 2