Mike Eason
Mike Eason

Reputation: 9713

Call an event from a base class

I have the following scenario:

public abstract class SomeBaseClass
{
    public event EventHandler SomeEvent;

    ...
}

public class SomeClass : SomeBaseClass
{
    public void DoSomething()
    {
        //TODO

        if (SomeEvent != null)
            SomeEvent(this, EventArgs.Empty);
    }
}

SomeBaseClass has an event which needs to be called in a base class, however this it isn't possible to directly call the event from a base class. To get around this, I can override the event in the base class, like so:

public class SomeClass : SomeBaseClass
{
    new public event EventHandler SomeEvent;

This is fine I guess, however my question is whether there is some kind of universal method, or good practice for implementing the functionality above?

The fact that it isn't possible to call an event from a base class suggests that I shouldn't really be doing this in the first place, perhaps the responsibility of calling the event should be only in SomeBaseClass?

Upvotes: 15

Views: 14165

Answers (4)

Mansur Kurtov
Mansur Kurtov

Reputation: 772

public delegate void ErrorHandler(string result);
public class BaseClass
{
   public event ErrorHandler OnError;
   protected void RaiseErrorEvent(string result)
   {
     OnError?.Invoke(result);
   }
 }
public class SampleClass:BaseClass
{
   public void Error(string s)
   {
     base.RaiseErrorEvent(s);
   }
}

Upvotes: 1

Fabjan
Fabjan

Reputation: 13676

I personally prefer to use delegates for that :

   public abstract class SomeBaseClass
    {
        public event EventHandler SomeEvent;
        protected Action<object, EventArgs> SomeEventInvoker;

        public SomeBaseClass()
        {
            SomeEventInvoker = new Action<object, EventArgs>((sender, args) => 
             { if (SomeEvent != null) SomeEvent(sender, args); });
        }
    }

   public class SomeClass : SomeBaseClass
    {
        public SomeClass()
        {
            DoSomething();
        }

        public void DoSomething()
        {                
            SomeEventInvoker(this, new EventArgs());
        }
    }

Upvotes: 0

Roland Mai
Roland Mai

Reputation: 31077

I would stay away from using new mainly because code will behave differently if an object is cast to the base class. Here's an alternative implementation:

public abstract class SomeBaseClass
{
    public virtual event EventHandler SomeEvent;

    protected virtual void HandleSomeEvent()
    {
        var ev = SomeEvent; // Localize event field used
        if (ev != null)
        {
            ev(this, EventArgs.Empty);
        }
    }
}

public class SomeClass : SomeBaseClass
{
    public override event EventHandler SomeEvent
    {
        add { base.SomeEvent += value; }
        remove { base.SomeEvent -= value; }
    }

    protected override void HandleSomeEvent()
    {
        base.HandleSomeEvent();
        // ... My own code here
    }
}

This allows for a great deal of flexibility. You can provide some implementation of event handling as well as allow the implementer to completely override the base class implementation.

Upvotes: 4

Patrick Hofman
Patrick Hofman

Reputation: 156918

That isn't allowed indeed. If I may recommend an alternative approach:

public abstract class SomeBaseClass
{
    public event EventHandler SomeEvent;

    protected void RaiseSomeEvent(EventArgs e)
    {
        var eh = SomeEvent;
        if (eh != null)
            eh(this, e);
    }
}

public class SomeClass : SomeBaseClass
{
    public void DoSomething()
    {
        //TODO
        RaiseSomeEvent(EventArgs.Empty);
    }
}

Note that I have moved the invocation of the event handler to the owning class, this is required by .NET / C# since only that class can invoke the event handler. Second, I have made the event handler thread safe by assigning it to eh first.

Never hide the base class' event by using the new keyword! You will get unexpected results when you use the base class' type as type for a variable or when the base class invokes the event.

Upvotes: 24

Related Questions