在派生类 C# 中引发基类事件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/780022/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Raise Base Class Events in Derived Classes C#
提问by Game_Overture
I have a base class DockedToolWindow : Form, and many classes that derive from DockedToolWindow. I have a container class that holds and assigns events to DockedToolWindow objects, however I want to invoke the events from the child class.
我有一个基类 DockedToolWindow : Form,以及许多派生自 DockedToolWindow 的类。我有一个容器类,用于保存事件并将事件分配给 DockedToolWindow 对象,但是我想从子类调用事件。
I actually have a question about how to implement what this MSDN siteis telling me to do. This section below is giving me the problem:
我实际上有一个关于如何实现这个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);
}
}
Sure this example compiles and works, but when I replace "ShapeChanged" with "Move" (an event I acquired from deriving from Form), it errors saying I cannot have Move on the right side without += or -=. I also removed the ShapeEventArgs generic tags.
当然这个例子可以编译和工作,但是当我用“Move”替换“ShapeChanged”(我从Form中获得的一个事件)时,它错误地说我不能在没有+=或-=的情况下在右侧移动。我还删除了 ShapeEventArgs 通用标签。
Any incite on why this isn't working? What's the difference between an event declared within the class and one that is inherited?
任何关于为什么这不起作用的煽动?在类中声明的事件与继承的事件有什么区别?
采纳答案by Groo
You cannot directly fire base class events. This is exactly the reason why you had to make your OnShapeChangedmethod protectedinstead of private.
您不能直接触发基类事件。这正是您必须使用OnShapeChanged方法protected而不是private.
Use base.OnMove()instead.
使用base.OnMove()代替。
回答by womp
The difference is scope. Inside your class, you can control how your event delegates are handled, however, your class cannot control what the base class is doing. It might be doing some crazy behind-the-scenes stuff with the event and its handlers. If you simply "reassigned" the Move event, you would be wiping out the multicast delegate list for the event.
区别在于范围。在您的类中,您可以控制事件委托的处理方式,但是,您的类无法控制基类正在做什么。它可能正在对事件及其处理程序做一些疯狂的幕后工作。如果您只是“重新分配”Move 事件,您将清除该事件的多播委托列表。
I'm guessing they put a compiler restriction on this because its a very unsafe practice, and would essentially give any descendant class the ability to destroy the event model of its parent.
我猜他们对此设置了编译器限制,因为这是一种非常不安全的做法,并且本质上会给任何后代类破坏其父类的事件模型的能力。
回答by Charlie
From the C# language spec, section 10.7 (emphasis added):
来自 C# 语言规范的第 10.7 节(强调):
Within the program text of the class or struct that contains the declaration of an event, certain events can be used like fields. To be used in this way, an event must not be abstract or extern, and must not explicitly include event-accessor-declarations. Such an event can be used in any context that permits a field. The field contains a delegate (§15) which refers to the list of event handlers that have been added to the event. If no event handlers have been added, the field contains null.
在包含事件声明的类或结构的程序文本中,某些事件可以像字段一样使用。要以这种方式使用,事件不能是抽象的或外部的,并且不能显式地包含事件访问器声明。此类事件可用于允许字段的任何上下文中。该字段包含一个委托(第 15 节),它指的是已添加到事件中的事件处理程序列表。如果未添加任何事件处理程序,则该字段包含 null。
Thus, the reason you can't treat the Move event like a field is that it is defined in a different type (in this case, your superclass). I agree with @womp's speculation that the designers made this choice to prevent unintended monkeying with the event. It seems obviously bad to allow unrelated types (types not derived from the type declaring the event) to do this, but even for derived types, it might not be desirable. They probably would have had to include syntax to allow the event declaration to be made privateor protectedwith respect to field-style usage, so my guess is that they opted to just disallow it entirely.
因此,您不能将 Move 事件视为字段的原因是它定义在不同的类型中(在本例中为您的超类)。我同意@womp 的猜测,即设计师做出这个选择是为了防止无意中与事件发生冲突。允许不相关的类型(不是从声明事件的类型派生的类型)这样做显然很糟糕,但即使对于派生类型,这也可能是不可取的。他们可能不得不包含允许进行事件声明private或protected关于字段样式使用的语法,所以我的猜测是他们选择完全禁止它。
回答by David Pope
You only need the code you posted in the class where the event itself is defined. All derived classes should simply call OnShapeChanged() or OnMove() directly, without the copying etc., so you shouldn't be writing that code at all in your classes (since the Move event is defined in the base).
您只需要在定义事件本身的类中发布的代码。所有派生类都应该直接调用 OnShapeChanged() 或 OnMove(),而无需进行复制等操作,因此您根本不应在类中编写该代码(因为 Move 事件是在基类中定义的)。
If you do need to do some kind of processing in the derived class (maybe you need to fiddle with your collection class?), you override the virtual OnXXX call and do you stuff before calling base.OnXXX(). In the MSDN article, the Circle class corresponds to your DockedToolWindow class. The same pattern should be available to your derived classes.
如果您确实需要在派生类中进行某种处理(也许您需要摆弄您的集合类?),您可以覆盖虚拟 OnXXX 调用并在调用 base.OnXXX() 之前执行操作。在 MSDN 文章中,Circle 类对应于您的 DockedToolWindow 类。您的派生类应该可以使用相同的模式。

