6

我有一个带有以下抽象事件的抽象基类

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

在我的实现中,我只是说

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

当我在实现中ValueChangedSignal尝试执行以下操作时

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

我收到 ReSharper 警告:Invocation of polymorphic field-like event

我检查了它背后的原因,但它virtual没有abstract在示例中使用:

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);
  }
}

上面的代码块使用覆盖事件声明来覆盖事件上添加和删除方法的实现。然后,该字段本身将存在于两个单独的实例中 - 一个在 Base 中,一个在 Derived 中。因此,在使用 Derived 时,您可能永远不会实例化 Base 的 MyEvent,除非您明确将其设置为某个值。并且,因此,在基类中引发事件的情况下的行为将与派生类中的行为不同。

我知道如果是的话,我会得到两个实例virtual。我会用实际实现隐藏基本实现,但是,当我使用时,abstract我从不做基本实现,是吗?我认为当我在某个字段上使用抽象时,我只是将实现转发给继承类,即我要求我的基类的用户实现抽象代码。

ReSharper 是否给了我错误的警告?还是我误解了什么?

4

1 回答 1

4

这不是一个错误的警告,Resharper 将您的注意力放在您的派生类也可以被继承和事件被覆盖的事实上。

让我们看一个例子:

    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
        }
    }

Main() 的结果:事件已处理

一切都按预期进行:我们订阅了事件 E,引发了事件 E,并且可以在屏幕上看到来自事件订阅的消息。

现在,如果我们从 DerivedClass 继承另一个类并像这样覆盖事件:

    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;
    }

事情发生了变化,现在 Main()什么也没输出。

这是因为对象b中有两个事件 E 的私有字段:一个来自 Derived 类,另一个来自 MostDerived。这正是 Resharper 所警告的。

如果您确定 Derived 类将永远不会被继承并且事件 E 被覆盖,请将 Derived 标记为已密封并且 Resharper 警告将消失。

于 2015-10-16T22:09:54.540 回答