【问题标题】:Why my custom event in C# is not raised?为什么没有引发我在 C# 中的自定义事件?
【发布时间】:2011-02-06 09:54:27
【问题描述】:

这不是我第一次在 C# 中创建自定义事件。令我惊讶的是为什么它在这种简单的情况下不起作用。

我有一个发布者和订阅者。在我的主程序中,我实例化了 1 个发布者和 2 个订阅者。当 addNews 被调用时,订阅者应该会收到事件 NewPublication:

static void Main()
{
    Publisher publisher = new Publisher();
    Subscriber subscriber1 = new Subscriber("John");
    Subscriber subscriber2 = new Subscriber("Jane");

    publisher.AddNews("custom event NewPublication");   
}

在subscriber.cs 我有:

public delegate void NewPublication(Publisher fromPublisher, String Message);

public class Publisher {

    private List<String> newsList = new List<String>();
    public event NewPublication newPublication;

    public void AddNews(String news) {
        newsList.Add(news);

        if (newPublication != null)
        {
            newPublication(this, news);
        }
    }
}

在订阅者中我有:

private String m_Name;
private event NewPublication newPublication;


public Subscriber(String name) {
    m_Name = name;
    newPublication += new NewPublication(subscriber_newPublication);
}

public void subscriber_newPublication(Publisher fromPublisher, String Message) {
    MessageBox.Show(m_Name + " is notified for " + Message);
}

它可以编译,但在运行时,该事件永远不会引发。为什么不?我怎样才能修复我的代码以便它确实被提升?

与 MSDN 示例代码真正不同的是: http://msdn.microsoft.com/en-us/library/w369ty8x.aspx

【问题讨论】:

    标签: c# .net events event-handling custom-event


    【解决方案1】:

    看来您实际上有 2 个 newPublication 事件:一个在订阅者中,一个在发布者中。您在 Publisher 中提出了一个,但订阅者只订阅他们自己的事件。

    以下是您的订阅者类的工作方式:

    private String m_Name;
    private Publisher m_Publisher;
    
    public Subscriber(String name, Publisher publisher) {
         m_Name = name;
         m_Publisher = publisher;
         m_Publisher.newPublication += new NewPublication(subscriber_newPublication);
    }
    
    public void subscriber_newPublication(Publisher fromPublisher, String Message) {
        MessageBox.Show(m_Name + " is notified for " + Message);
    }
    

    为了方便使用,您可能希望在 Publisher 类中引入订阅方法,如下所示:

    public Subscriber Subscribe(String name)
    {
         return new Subscriber(name, this);
    }
    

    请注意,附加但从未分离的事件处理程序可能会导致 .NET 应用程序中的内存泄漏。当您不再需要事件处理程序时,始终使用 -= 运算符分离它们(例如,在 WinForms 应用程序中,我通常在触发 FormClosed 事件时分离控制事件的事件处理程序)。 Here 是一篇深入讲解的好文章,here 是另一篇演示内存泄漏检测的文章。

    对于高级事件概念,您可能需要熟悉 F# 和 Reactive Framework 的事件模型(它们也没有内存泄漏),如this 系列文章中所述。

    【讨论】:

    • @user310291:我更新了我的帖子,提到了 F# 和 Rx.NET 的事件模型。如果您想深入研究该主题,我建议您看一下它们,以便您至少熟悉基础知识。你永远不知道它们什么时候会派上用场。 :)
    【解决方案2】:

    您已经声明了两个不同的事件。您的发布者实例和订阅者实例没有以任何方式连接。因此,在发布者中引发事件不会触发订阅者中的处理程序。

    你需要做的是示意性的:

    publisher.newPublication += subscriber1.subscriber_newPublication;
    publisher.newPublication += subscriber2.subscriber_newPublication;
    

    将此代码放在这些类的实例化和对AddNews() 的调用之间。

    更新:因此在Subscriber 类中声明newPublication 完全没有用,应从该类中删除。如果需要,您可以将Publisher 实例传递给Subscriber 的构造函数,以在Subscriber 内进行事件连接。但是,将事件连接代码保留在事件发布者和事件订阅者之外通常是一个好主意。

    【讨论】:

    • 但是,这也不会连接这两个事件。由于委托是值类型,因此您所做的只是将subscriber1.newPublication 和subscriber2.newPublication 的事件处理程序复制到publisher.newPublication。添加到任一订阅者的任何其他事件处理程序都不会出现在发布者中。
    • @ShdNx 嘿,对,我的意思实际上是subscriber_newPublication。感谢您注意到这个错误。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多