.net 默认事件处理程序
在我的产品中,我需要处理范围内的事件。为此,我使用了如下代码:
public class Global
{
public static event EventHandler<MyEventArgs> Message;
public static void ShowMessage();
}
现在假设我有一个 WinForms 用户界面。在表单的代码中,我将订阅此事件并以某种默认方式处理它(例如,通过使用 System.Windows.Forms.MessageBox.Show() 方法)。现在的问题是如何允许用户创建派生表单并覆盖我的默认消息事件处理程序实现?
仅使用自定义实现第二次订阅事件并不能解决问题(两个事件处理程序都将被执行,并且可能会显示两个消息框)。我看到的选项有:
//call OnSubscribeToMessageEvent() from either form's constructor or OnLoad event handler
protected virtual void OnSubscribeToMessageEvent()
{
Global.Message += new EventHandler<MyEventArgs>(Global_Message);
}
private void Global_Message(object sender, MyEventArgs e)
{
//my default implementation
}
或
//subscribe in either form's constructor or OnLoad event handler
protected virtual void Global_Message(object sender, MyEventArgs e)
{
//my default implementation
}
哪个版本更好,为什么?或者也许还有其他选择?
In my product I need process wide events. For that I used code like this:
public class Global
{
public static event EventHandler<MyEventArgs> Message;
public static void ShowMessage();
}
Now let's say I have a WinForms user interface. In form's code I will subscribe to this event and handle it in some default way (eg. by using System.Windows.Forms.MessageBox.Show() method). Now the question is how do I allow user to create derived form and override my default Message event handler implementation?
Just subscribing to the event for the second time with custom implementation doesn't solve the problem (both event handlers would be executed and potentially two message boxes shown). The options I see are either:
//call OnSubscribeToMessageEvent() from either form's constructor or OnLoad event handler
protected virtual void OnSubscribeToMessageEvent()
{
Global.Message += new EventHandler<MyEventArgs>(Global_Message);
}
private void Global_Message(object sender, MyEventArgs e)
{
//my default implementation
}
or
//subscribe in either form's constructor or OnLoad event handler
protected virtual void Global_Message(object sender, MyEventArgs e)
{
//my default implementation
}
Which version is better and why? Or maybe there are any other options?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
。是的,你担心这一点是对的。此类事件订阅非常变化无常,事件源总是比订阅者寿命更长。据我所知,框架中只有一个类可以执行此操作,即 SystemEvents。问题是每个订阅者在其生命周期结束时都必须非常小心取消订阅自己,否则该对象将永远保持引用状态。很难诊断的内存泄漏。
这里更好的模式是使用接口。让我们声明一个:
现在您可以让一个表单实现该接口:
Register 方法向 GlobalMessages 类注册该表单,Dispose 事件确保该类可以检测到该表单正在死亡:
调用 GlobalMessages.Notify() 获取 OnMessage () 方法在所有实时表单实例中运行。这种方法的主要优点是客户端程序员永远不会搞砸。
Yes, you're right to worry about this. These kind of event subscriptions are very fickle, the event source always outlives the subscriber. There's only one class in the framework I know that does this, SystemEvents. The problem is that every subscriber has to very carefully unsubscribe itself when its lifetime ends or the object will stay referenced forever. A memory leak that's very hard to diagnose.
A better pattern here is to use an interface. Let's declare one:
Now you can have a form implement the interface:
The Register method registers the form with the GlobalMessages class, the Dispose event ensures that the class can detect that the form is dying:
Call GlobalMessages.Notify() to get the OnMessage() method to run in all live form instances. The major advantage of this approach is that a client programmer can never screw up.
我会让派生类重写 Global_Message。事件的订阅是通用的,为什么你想在每个孩子中再次实现它?如果您的子类只想向其添加一些装饰并使用默认行为,它还为您提供了调用base.Global_Message(sender, e) 的选项。
I would let the derived class override the
Global_Message
. The subscription to the event is generic and why would you want to implement it in every child again? It also gives you the option to callbase.Global_Message(sender, e)
in case your child class just wants to add some decoration to it and use the default behaviour otherwise.我更喜欢您的第二个示例,因为这样,扩展基类的类只需重写一个方法,而不必从事件中删除基类添加的处理程序。
I would prefer your second example, as that way, classes that extend your base class only have to override one method and do not have to remove the handler added by the base class from the event.
关键是添加virtual关键字,以便派生类型可以覆盖该方法,并且将调用它们创建的方法。
The key is adding the virtual keyword, so that a derived type can overide the method and the method they created will be called instead.
现在您已经为两者添加了虚拟,如果他们不希望订阅事件,我会选择第一个并覆盖订阅该事件的那个。
虽然还有另一种选择,但称之为#3。
那么继承的类可能会在某处执行以下操作:(注意 -=)
Now that you've added virtual to both, I'd go with the first and override the one that subscribes to the event, if they didn't want the event subscribed to.
Though there is another option, call it #3.
Then potentially an inherited class could do somewhere: (note the -=)