C# 在什么情况下我需要使用C的事件

C# 在什么情况下我需要使用C的事件,c#,.net,events,C#,.net,Events,我正在研究C语言中的事件,但是没有太多的文章或信息告诉我在哪里或什么样的位置需要使用事件 有人能给我举个真实世界的例子,让他们更容易理解吗 提前感谢。假设您正在开发UI。创建一个小部件并将其添加到主窗体。当小部件中发生某些事情时,您可以使用事件触发表单上的某些操作—禁用其他按钮,等等 就像按钮的点击事件一样。我通常看到的最实际的例子是用户交互。让我们使用一个按钮作为一个具体的例子。当点击按钮时,您显然希望发生一些事情。假设我们称之为SaveSettings。但是,我们不希望将SaveSettin

我正在研究C语言中的事件,但是没有太多的文章或信息告诉我在哪里或什么样的位置需要使用事件

有人能给我举个真实世界的例子,让他们更容易理解吗


提前感谢。

假设您正在开发UI。创建一个小部件并将其添加到主窗体。当小部件中发生某些事情时,您可以使用事件触发表单上的某些操作—禁用其他按钮,等等


就像按钮的点击事件一样。

我通常看到的最实际的例子是用户交互。让我们使用一个按钮作为一个具体的例子。当点击按钮时,您显然希望发生一些事情。假设我们称之为SaveSettings。但是,我们不希望将SaveSettings硬编码到按钮中。按钮将命令进行保存设置。显然,这阻止了按钮的可重用性——除了设置对话框之外,我们不能在任何地方使用调用SaveSettings的按钮。为了避免为每个按钮编写相同的按钮代码,每个按钮调用不同的函数,我们使用一个事件

该按钮不是直接调用函数,而是宣布已单击该函数。从那以后,按钮的责任就结束了。其他代码可以监听该公告或事件,并执行特定的操作

因此,在我们的SaveSettings示例中,设置对话框代码找到OK按钮并侦听其I Get clicked公告,当它被触发时,调用SaveSettings


事件可能变得非常强大,因为任意数量的不同侦听器都可以等待同一事件。事件可以调用许多东西。

当然可以。将事件视为当代码没有直接调用的系统中的某些内容完成时发生的通知。在C语言中,当事件触发时,很容易让代码运行

例如,当用户按下按钮时,将引发事件或后台网络操作完成时。在C语言中,使用+=语义附加到事件,当事件触发时,该事件将被“通知”

我为您制作了一个简单的C winforms程序–在其中,我使用Visual Studio“Designer”添加了一个按钮,我只是将一个按钮从工具箱拖动到窗口

您将看到行“button1.Click”-在本例中,我希望在引发“Click”事件时执行一些操作

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace events
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            button1.Click += new EventHandler(button1_Click);
        }

        void button1_Click(object sender, EventArgs e)
        {
            MessageBox.Show("Hi!");
        }
    }
}
您还将在实践中看到其他类型的事件,例如:

网络运行已完成 例如,调整窗口大小的用户界面 10分钟后启动计时器
正如Chris Gray所说,一个用途是在代码没有直接调用的情况下发出信号。这里最常见的原因可能是GUI上的用户操作。另一个例子可能是在另一个线程上完成的异步操作

使用事件的另一个原因是当您不知道谁可能对刚刚发生的事情感兴趣时。引发事件的类在设计时不需要知道其他类可能感兴趣的实例的数量

class Raiser {

   public DoSomething() {
      //Do something long winded.
      OnDidSomething(new DidSomethingEventArgs());
   }

   public EventHandler<DidSomethingEventArgs> DidSomething;

   private OnDidSomething(DidSomethingEventArgs e) {
      if (DidSomething != null)
         DidSomething(this, e);
   }
}
以及:

现在,当对Raiser实例调用DoSomething方法时,ListenerA和ListenerB的所有实例都将通过DidSomething事件得到通知。请注意,侦听器类可以很容易地位于raiser的不同程序集中。它们需要一个对raiser程序集的引用,但不需要对其侦听器程序集的引用

请注意,上面的简单Raiser示例可能会导致多线程程序出现一些问题。更可靠的示例将使用以下内容:

class Raiser {

   public DoSomething() {
      //Do something long winded.
      OnDidSomething(new DidSomethingEventArgs());
   }

   #region DidSomething Event

   private object _DidSomethingLock = new object();
   private EventHandler<DidSomethingEventArgs> _DidSomething;

   public EventHandler<DidSomethingEventArgs> DidSomething {
      add { lock(_DidSomethinglock) _DidSomething += value; }
      remove { lock(_DidSomethinglock) _DidSomething -= value; }
   }

   OnDidSomething(DidSomethingEventArgs e) {
      EventHandler<DidSomethingEventArgs> handler;
      lock (_DidSomethingLock)
         handler = _DidSomething;
      if (handler == null)
         return;
      try {
         DidSomething(this, e);
      } catch (Exception ex) {
         //Do something with the exception
      }
   }

   #endregion
}

这确保了另一个线程在添加事件时添加或删除侦听器不会引起问题。


如果正在创建和销毁侦听器类的实例,这里使用的简单侦听器也会导致内存泄漏。这是因为Raiser实例被传递,并在每个侦听器订阅事件时存储对它们的引用。这足以防止垃圾收集器在删除对侦听器的所有显式引用时正确清理侦听器。解决这个问题的最佳方法可能是让侦听器实现IDisposable接口,并取消订阅Dispose方法中的事件。然后,您只需要记住调用Dispose方法。

您可能需要澄清您是要求提供订阅按钮单击之类的事件的示例,还是发布自己的事件。我要求提供这两种示例。广播和订阅。谢谢,但是你能举一个创建我们自己的广播活动的例子,以及如何订阅它们吗。
class ListenerB {

   private Raiser r;

   ListenerB(Raiser r) {
      this.r = r;
      r.DidSomething += R_DidSomething;
   }

   R_DidSomething(object sender, DidSomethingEventArgs e) {
      //Do something with the result.
   }
}
class Raiser {

   public DoSomething() {
      //Do something long winded.
      OnDidSomething(new DidSomethingEventArgs());
   }

   #region DidSomething Event

   private object _DidSomethingLock = new object();
   private EventHandler<DidSomethingEventArgs> _DidSomething;

   public EventHandler<DidSomethingEventArgs> DidSomething {
      add { lock(_DidSomethinglock) _DidSomething += value; }
      remove { lock(_DidSomethinglock) _DidSomething -= value; }
   }

   OnDidSomething(DidSomethingEventArgs e) {
      EventHandler<DidSomethingEventArgs> handler;
      lock (_DidSomethingLock)
         handler = _DidSomething;
      if (handler == null)
         return;
      try {
         DidSomething(this, e);
      } catch (Exception ex) {
         //Do something with the exception
      }
   }

   #endregion
}