Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing abstract event gives "Invocation of polymorphic field-like event" warning from ReSharper

I have an abstract base class with the following abstract event

public abstract class SignalWrapperBase<T> : IReadOnlySignal<T> {
  public abstract event Action<IReadOnlySignal<T>, Sample<T>> Updated;
  ...
}

in my implementation i simply say

public class ValueChangedSignal : SignalWrapperBase<T> {
  public override event Action<IReadOnlySignal<T>, Sample<T>> Updated;
  ...
}

and when I in the implementation ValueChangedSignal try to perform the following

if (Updated != null) { Updated(this, sample); }

I get a ReSharper warning: Invocation of polymorphic field-like event.

I checked the reasoning behind it, but it uses virtual not abstract in the example:

public class Base
{
  public virtual event EventHandler MyEvent;
}

public class Derived : Base
{
  public override event EventHandler MyEvent;
  public void SomeMethod()
  {
    var args = ...;
    MyEvent(this, args);
  }
}

The above block of code uses an overriding event declaration to override the implementation of the add and remove methods on an event. The field itself will then exist in two separate instances - one in Base and one in Derived. As a consequence, when working with Derived, you're likely to never instantiate the Base's MyEvent unless you explicitly set it to some value. And, as a result of that, the behavior in the case when the event is raised in the base class would differ from that in the derived class.

I get that I would get two instances if it were virtual. I would be hiding the base implementation with the actual implementation, however, when I use abstract I am never making a base implementation, am I? I thought that when I use abstract on some field I am simply forwarding the implementation to the inheriting class, i.e., I am requiring the user of my base class to implement the abstract code.

Is ReSharper giving me a wrong warning? Or am I misunderstanding something?

like image 986
André C. Andersen Avatar asked Jul 15 '13 11:07

André C. Andersen


1 Answers

It's not a false warning and Resharper puts your attention on fact that your derived class can be inherited as well and event overridden.

Let's see an example:

    static void Main(string[] args)
    {
        Base b = new Derived();

        b.E += (sender, eventArgs) => { Console.WriteLine("Event Handled"); };
        b.Raise();
    }

    abstract class Base
    {
        public abstract event EventHandler E;
        public abstract void Raise();
    }

    class Derived : Base
    {
        public override event EventHandler E;
        public override void Raise()
        {
            if (E != null)
                E(this, null); // Resharper: Invocation of polymorphic field-like events
        }
    }

Result of Main(): Event Handled

Everything works as expected: we subscribed to event E, raised event E and can see message from the event subscribtion on the screen.

Now, if we inherit another class from DerivedClass and override event like this:

    static void Main(string[] args)
    {
        Base b = new MostDerived();

        b.E += (sender, eventArgs) => { Console.WriteLine("Event Handled"); };
        b.Raise();
    }

    class MostDerived : Derived
    {
        public override event EventHandler E;
    }

things change and now Main() puts out nothing.

It happens because there is two private fields of event E in object b: one comes from Derived class and the other from MostDerived. That's exactly what Resharper warned about.

If you're sure Derived class will never be inherited and event E overriden, mark Derived as sealed and Resharper warning will disappear.

like image 87
Vladimir Dorokhov Avatar answered Oct 21 '22 19:10

Vladimir Dorokhov