nopara73
nopara73

Reputation: 512

.NET - Should I directly Invoke events?

I am stuck with a pattern for a long time now and recently I realized I forgot why I got used to do things this way.

public event EventHandler<string> SomethingChanged;
private void OnSomethingChanged(string something) => SomethingChanged?.Invoke(this, something);

So, when I want to invoke the event I call OnSomethingChanged(this, something);. Why not just do SomethingChanged?.Invoke(this, state); directly?

Feels like quite a simplification. Is it possible this OnSomethingChanged pattern served a purpose back then, when C# syntax was more complicated, but today it's mostly unnecessary?

In fact, since this pattern is quite long, I always just copy paste it and replace the relevant parts. Ironically, I can recall a couple of times when this copy pasting resulted debugging my software just to find out I made a mistake here, because of being in a hurry. This also makes invoking directly SomethingChanged preferable.

Upvotes: 1

Views: 981

Answers (1)

ASh
ASh

Reputation: 35681

consider the following example:

public class BaseClass 
{
    private int id;
    public int Id 
    { 
        get { return id; }
        set { id = value; SomethingChanged(this, "id"); }
    }

    public event EventHandler<string> SomethingChanged;
}

public class DerivedClass : BaseClass
{
    private string name;
    public string Name 
    { 
        get { return name; }
        set 
        { 
            name = value; 
            //// cannot be invoked directly here
            // SomethingChanged(this, "name"); 
        }
    }
}

c# documentations mentions this case specifically

Events are a special type of delegate that can only be invoked from within the class that declared them. Derived classes cannot directly invoke events that are declared within the base class. Although sometimes you may want an event that can only be raised by the base class, most of the time, you should enable the derived class to invoke base class events. To do this, you can create a protected invoking method in the base class that wraps the event. By calling or overriding this invoking method, derived classes can invoke the event indirectly.

private method in the base class which triggeres event isn't much help, it should be protected. It is also sensible to make that method virtual to allow derived class add some functionality before/after notifing event subscrivers:

public class BaseClass 
{
    private int id;
    public int Id 
    { 
        get { return id; }
        set { id = value; OnSomethingChanged( "id"); }
    }

    public event EventHandler<string> SomethingChanged;

    protected virtual void OnSomethingChanged(string something)
    {
        SomethingChanged(this, something);
    }
}

public class DerivedClass : BaseClass
{
    private string name;
    public string Name 
    { 
        get { return name; }
        set 
        { 
            name = value; 
            OnSomethingChanged("name"); 
        }
    }

    protected override void OnSomethingChanged(string something)
    {
        base.OnSomethingChanged(something + " (event triggered from derived class)");
    }
}
public static void Main(string[] args)
{
    var item = new DerivedClass();
    item.SomethingChanged += (e,s) => Console.WriteLine(s);
    item.Id = 5;
    item.Name = "abc";
}

this modified example prints:

id (event triggered from derived class)
name (event triggered from derived class)

Upvotes: 4

Related Questions