c# - .net 默认事件处理程序

标签 c# .net design-patterns

在我的产品中,我需要处理范围内的事件。为此,我使用了这样的代码:

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
}

哪个版本更好,为什么?还是有其他选择?

最佳答案

I still have some doubts as I have never seen such a design pattern in any .NET library

是的,你担心这个是对的。这种事件订阅非常善变,事件源总是比订阅者长。我所知道的框架中只有一个类可以执行此操作,SystemEvents。问题在于每个订阅者都必须非常小心在其生命周期结束时自行取消订阅,否则该对象将永远被引用。很难诊断的内存泄漏。

这里更好的模式是使用接口(interface)。让我们声明一个:

public class MyEventArgs { /* etc.. */ }

public interface IGlobalNotification {
    event EventHandler Disposed;
    void OnMessage(MyEventArgs arg);
}

现在您可以让表单实现接口(interface):

public partial class Form1 : Form, IGlobalNotification {
    public Form1() {
        InitializeComponent();
        GlobalMessages.Register(this);
    }

    void IGlobalNotification.OnMessage(MyEventArgs arg) {
        // do something
    }
}

Register 方法向 GlobalMessages 类注册表单,Dispose 事件确保该类可以检测到表单正在消失:

public static class GlobalMessages {
    public static void Register(IGlobalNotification listener) {
        listener.Disposed += delegate { listeners.Remove(listener); };
        listeners.Add(listener);
    }
    public static void Notify(MyEventArgs arg) {
        foreach (var listener in listeners) listener.OnMessage(arg);
    }

    private static List<IGlobalNotification> listeners = new List<IGlobalNotification>();
}

调用 GlobalMessages.Notify() 以获取 OnMessage() 方法以在所有实时窗体实例中运行。这种方法的主要优点是客户端程序员永远不会搞砸。

关于c# - .net 默认事件处理程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5783797/

相关文章:

design-patterns - 说装饰器比适配器更透明是什么意思?

C#服务层设计模式

c# - 位智深层链接

c# - CaSTLe Windsor ASP.NET MVC 4 和 Web API 相同的应用程序。仅当 MVC Controller 没有依赖项时?

.net - 多个值的 IComparer

c# - 我如何获得 XElement 的第一个 child ?

.NET:有什么方法可以判断对象何时被处理/垃圾收集?

c# - 在 C# 中使用通知的生产者和消费者

c# - 在 C# 中使用反射在运行时加载类型

c# - 通过 C# 中扩展方法的反射获取泛型重载