【问题标题】:c# event handler being added twicec# 事件处理程序被添加两次
【发布时间】:2011-07-08 00:45:52
【问题描述】:

这是一个虚构的例子,但我想知道如果 InitialiseTimer 函数被调用两次会发生什么。计时器经过功能是否被触发两次。如果将函数设为静态,这会改变吗?

    private static void InitialiseTimer()
    {
            TheTimer = new System.Timers.Timer();
            TheTimer.Interval = 400;
            TheTimer.Elapsed += new ElapsedEventHandler(TheTimer_Elapsed);
            TheTimer.AutoReset = false;
    }   

    public void TheTimer_Elapsed(object sender, ElapsedEventArgs e)
    {
        //Do stuff in here
    }

我打算在下面使用来防止这种情况发生

Has an event handler already been added?

谢谢, 理查德

【问题讨论】:

    标签: c# event-handling timer


    【解决方案1】:

    如果您注册了两次事件处理程序,则每次引发事件时都会调用两次。

    如果您将 TheTimer_Elapsed 设为静态,这不会改变,因为您仍将持有对该静态方法的两个引用。

    在大多数情况下,无需编写复杂的内容,例如 Blair Conrad 在您链接到的问题中发布的内容。每次使用+= 时不要忘记使用-=,这样您就安全了。

    【讨论】:

      【解决方案2】:

      我认为以下演示了该场景并且确实触发了两次,还建议对应该修复该行为的 Init 方法进行简单更改(注释代码)。 (顺便说一句,不是线程安全的,需要额外的锁)

      [TestClass]
      public class UnitTest1
      {
          [TestMethod]
          public void TestMethod1()
          {
              var counter = 0;
              var ts = new ThreadStart(() =>
                  {
      
                      Foo.Fired += (o, e) =>
                          {
                              counter++;
                          };
                      Foo.InitialiseTimer();
                      Foo.InitialiseTimer();
                  });
              var t = new Thread(ts);
              t.Start();
      
              Thread.Sleep(30);
              Assert.AreEqual(1, counter);
          }
      }
      
      public class Foo
      {
          private static System.Timers.Timer TheTimer = null;
      
          public static event EventHandler Fired;
      
          public static void InitialiseTimer()
          {
              //if (TheTimer != null)
              //{
              //    TheTimer.Stop();
              //    TheTimer = null;
              //}
              TheTimer = new System.Timers.Timer();
              TheTimer.Interval = 10;
              TheTimer.Elapsed += new ElapsedEventHandler(TheTimer_Elapsed);
              TheTimer.AutoReset = false;
              TheTimer.Start();
          }
      
          public static void TheTimer_Elapsed(object sender, ElapsedEventArgs e)
          {
              //Do stuff in here
              if (Fired != null)
              {
                  Fired(null, null);
              }
          }
      }
      

      【讨论】:

        【解决方案3】:

        如果您调用 InitialiseTimer 方法两次,您将创建两个 Timer,每个 Timer 都将仅附加一个事件处理程序,但它们可能会同时失效。这并不是关于是否让方法静态,更多的是关于方法本身,您可以检查 TheTimer 是否为空,只有当它为空时才执行其余操作,因此您只分配一次。

        【讨论】:

          【解决方案4】:

          如果事件被注册两次,你将有两次执行。

          可以检查event是否为null,问题就解决了。

          【讨论】:

          • 检查空值如何解决这个问题?如果已为此事件注册了其他处理程序怎么办?
          • 这将是对新创建的 Timer 实例的空检查,而不是在上一次调用中创建的实例,因此这并不能真正解决任何问题。但是,空检查字段TheTimer 将解决问题。
          • 当然,我认为您必须检查同一计时器上的事件是否为空,而不是新创建的。
          【解决方案5】:

          无论是否静态,您都在重新创建计时器。因此,您可以多次调用 InitialiseTimer,而无需添加多个处理程序。不过你最终会得到很多计时器......

          【讨论】:

            猜你喜欢
            • 2012-03-30
            • 1970-01-01
            • 2010-10-30
            • 2010-12-04
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多