我有一个带有以下抽象事件的抽象基类
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警告:调用多态字段事件。
我查看了其背后的reasoning,但在示例中使用了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);
}
}
上面的代码块使用覆盖事件声明来覆盖事件上的add和remove方法的实现。然后,字段本身将存在于两个单独的实例中 - 一个在Base中,一个在Derived中。因此,在使用Derived时,除非明确将其设置为某个值,否则您可能永远不会实例化Base的MyEvent。并且,因此,在基类中引发事件的情况下的行为将与派生类中的行为不同。
如果是virtual
,我会得到两个实例。我将使用实际实现隐藏基本实现,但是,当我使用abstract
时,我从不进行基本实现,是吗?我认为当我在某些字段上使用abstract时,我只是将实现转发给继承类,即,我要求我的基类的用户实现抽象代码。
ReSharper是否给我一个错误的警告?或者我误解了什么?
答案 0 :(得分:2)
这不是一个错误的警告,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()推出 nothing 。
这是因为对象 b 中有两个事件E的私有字段:一个来自Derived类,另一个来自MostDerived。这正是Resharper所警告的。
如果您确定Derived类永远不会被继承并且事件E覆盖,则将Derived标记为密封,并且Resharper警告将消失。