题
我有一个基类 DockedToolWindow :Form 以及许多从 DockedToolWindow 派生的类。我有一个容器类,它保存事件并将其分配给 DockedToolWindow 对象,但是我想从子类调用事件。
我实际上有一个关于如何实现这个的问题 MSDN 站点 是告诉我要做什么。下面的这一部分给了我问题:
// The event. Note that by using the generic EventHandler<T> event type
// we do not need to declare a separate delegate type.
public event EventHandler<ShapeEventArgs> ShapeChanged;
public abstract void Draw();
//The event-invoking method that derived classes can override.
protected virtual void OnShapeChanged(ShapeEventArgs e)
{
// Make a temporary copy of the event to avoid possibility of
// a race condition if the last subscriber unsubscribes
// immediately after the null check and before the event is raised.
EventHandler<ShapeEventArgs> handler = ShapeChanged;
if (handler != null)
{
handler(this, e);
}
}
当然,这个例子可以编译并工作,但是当我用“Move”(我从 Form 派生获得的一个事件)替换“ShapeChanged”时,它错误地说我不能在没有 += 或 -= 的情况下将 Move 放在右侧。我还删除了 ShapeEventArgs 通用标签。
任何煽动为什么这不起作用?在类中声明的事件和继承的事件之间有什么区别?
解决方案
您不能直接解雇基类事件。这正是您必须制作您的 OnShapeChanged
方法 protected
代替 private
.
利用 base.onmove() 反而。
其他提示
根据C#语言规范第10.7节(添加了强调):
在包含事件声明的类或结构的程序文本中,可以像字段一样使用某些事件. 。要以这种方式使用,事件不得是抽象或外部,并且不得明确包含事件访问者 - 销售。这样的事件可以在任何允许字段的上下文中使用。该字段包含一个代表(§15),该代表指的是已添加到活动的事件处理程序列表。如果没有添加事件处理程序,则该字段包含空。
因此,您无法将移动事件视为字段的原因是它以其他类型定义(在这种情况下为您的超类)。我同意 @WOMP的猜测,即设计师做出了选择,以防止事件发生意想不到的猴子。允许允许无关类型(不是从声明事件的类型派生的类型)来执行此操作似乎很不好,但是即使对于派生类型,也可能是不可取的。他们可能不得不包括语法以允许发表事件声明 private
或者 protected
关于现场风格的使用,所以我的猜测是他们选择完全禁止它。
区别在于范围。在您的班级内部,您可以控制事件代表的处理方式,但是,您的班级无法控制基类在做什么。它可能会在活动及其处理程序中做一些疯狂的幕后工作。如果您简单地“重新分配”了移动事件,您将删除该事件的多播代表列表。
我猜他们对此对编译器进行了限制,因为它是一种非常不安全的练习,从本质上讲,任何后代类都可以破坏其父母的事件模型。
您只需要在定义事件本身的类中发布的代码。所有派生类都应该直接直接调用 OnShapeChanged() 或 OnMove(),而不进行复制等操作,因此您根本不应该在类中编写该代码(因为 Move 事件是在基类中定义的)。
如果您确实需要在派生类中进行某种处理(也许您需要摆弄集合类?),您可以重写虚拟 OnXXX 调用并在调用 base.OnXXX() 之前进行处理。在 MSDN 文章中,Circle 类对应于您的 DockedToolWindow 类。相同的模式应该可用于您的派生类。