dumbledad
dumbledad

Reputation: 17527

Invoke base event handler in C# 6

I have a simple abstract class:

abstract class Lesson
{
    public event EventHandler<SpeakEventArgs> Speak;
    public string OpeningMessage { get; set; }
    public string ClosingMessage { get; set; }
    public bool completed { get; private set; } = false;
    abstract public void Do();
}

And a simple sub-class:

class BubbleSort : Lesson
{
    public override void Do()
    {
        base.Speak?.Invoke(this, new SpeakEventArgs { Message = OpeningMessage });
    }
}

The sub-class uses the C# 6 null-conditional operator ?.. This code gives the error

The event 'Lesson.Speak' can only appear on the left hand side of += or -= (except when used within the type 'Lesson')

Surely as a sub-class I am here within the type 'Lesson'? How do I do this invocation of the base class event within the sub-class?

Upvotes: 1

Views: 2405

Answers (3)

MikeT
MikeT

Reputation: 5500

You can't Invoke an event in any class other than the one that it was declared in

instead i would suggest creating a raise method in your base class that performs the required checks then raises the event for you

protected void raiseSpeak(SpeakEventArgs args)
{
    this.Speak?.Invoke(sender, args);
}

or in your case just remove the abstract from do and raise the event in the do method in your lesson class, which you can then override for extra functionality

abstract class Lesson
{
    public event EventHandler<SpeakEventArgs> Speak;

    public virtual void Do()
    {
        this.Speak?.Invoke(sender, args);
    }
}

class BubbleSort : Lesson
{
    public override void Do()
    {
        base.Do();
        //do something BubbleSort related
    }
}

Upvotes: 1

user406570
user406570

Reputation:

You will have to provide a raise method in your abstract class, eg:

abstract class Lesson
{
    public event EventHandler<SpeakEventArgs> Speak;
    public string OpeningMessage { get; set; }
    public string ClosingMessage { get; set; }
    public bool completed { get; private set; } = false;
    abstract public void Do();

    protected virtual void RaiseSpeak(object sender, SpeakEventArgs args)
    {
        this.Speak?.Invoke(sender, args);
    }
}

which you then can override optionally, eg:

class BubbleSort : Lesson
{
    protected override void RaiseSpeak(object sender, SpeakEventArgs args)
    {
        // your logic here

        base.RaiseSpeak(sender, args);
    }

    public override void Do()
    {
        this.RaiseSpeak(this, new SpeakEventArgs() { Message = OpeningMessage });
    }
}

Upvotes: 0

ken2k
ken2k

Reputation: 48995

You cannot directly invoke an event from outside the class that defines it, even from a sub-class.

Solution: use a protected method to fire it:

internal abstract class Lesson
{
    public event EventHandler<SpeakEventArgs> Speak;

    public string OpeningMessage { get; set; }
    public string ClosingMessage { get; set; }
    public bool completed { get; private set; } = false;

    abstract public void Do();

    protected void DoSpeak(SpeakEventArgs e)
    {
        if (this.Speak != null)
        {
            this.Speak(this, e);
        }
    }
}

internal class BubbleSort : Lesson
{
    public override void Do()
    {
        base.DoSpeak(new SpeakEventArgs { Message = OpeningMessage });
    }
}

Upvotes: 1

Related Questions