Search code examples
c#eventspartial-classes

Invoking an event from partial class is not possible


I have the following class structure:

    public abstract class Base : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
    }
    
    internal partial class ImplBase : Base {
    }
    
    internal partial class ImplBase {
        void someFunc(){
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("propName"));
        }
    }

Why does the language disallow raising an event from a partial class?

See the snippet here: https://dotnetfiddle.net/k8catR


Solution

  • You can reproduce the error compilation without partial class :

    public abstract class Base : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
    }
    
    internal class ImplBase : Base
    {
        void someFunc()
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("propName"));
        }
    }
    

    This code has the same error message, it isn't a partial class limitation. It's a heritage limitation :

    https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/events/how-to-raise-base-class-events-in-derived-classes

    When you create a class that can be used as a base class for other classes, you should consider the fact that 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.

    You need raise the event in the class that declare the event. You can do this in a method and reuse the method in sub-classes :

    public abstract class Base : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
    
        protected void RaisePropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    
    internal partial class ImplBase : Base
    { }
    
    internal partial class ImplBase
    {
        void someFunc()
        {
            RaisePropertyChanged("propName");
        }
    }