如何访问Timer所连接的对象?

时间:2011-10-03 13:27:58

标签: c# event-handling

我有一个编程问题,我认为这是由于我在使用事件和代表时的生锈...

我有代码:

public void DoStuff()
        {
            List<IProcess> processorsForService1  = processorsForService1 = ProcessFactory.GetProcessors();

            foreach (IProcess p in processorsForService1)
            {
                if (p.ProcessTimer != null)
                {
                    p.ProcessTimer.Elapsed += new ElapsedEventHandler(IProcess_Timer_Elapsed);
                }
            }
        }

  private void IProcess_Timer_Elapsed(object sender, ElapsedEventArgs e)
            {
                IProcess p = (IProcess)sender;
                p.Step_One();
                p.Step_Two();
            }

但是当我到达事件处理程序时,我在第一行获取了p的空引用异常。

如何在此实例中将参数传递给处理程序?

4 个答案:

答案 0 :(得分:1)

看起来您正在使用System.Timers.Timer,如果您要使用System.Threading.Timer,那么您可以传递state对象,在这种情况下,该对象可能是所需的实例一个类,即计时器的“所有者”。通过这种方式,您可以像以前在事件处理程序中的实现经验一样定义方法体,现在签名如下:

private void MyTimerCallbackMethod(object state)
{

}

然后,在创建计时器实例时,您可以执行以下操作:

var timerCallback = new TimerCallback(MyTimerCallback);
var timer = new Timer(timerCallback, myStateObject, 
    Timeout.Infinite, Timeout.Infinite);

然后,使用timer.Change(whenToStart, interval)启动计时器。

答案 1 :(得分:0)

发件人是计时器对象,而不是与处理委托关联的对象。首先,事件可以有多个处理程序。

您可以做的是创建一个可以使用变量捕获访问IProcess的委托。

答案 2 :(得分:0)

如果您使用lambda而不是委托,则可以从lambda引用该类,因为它仍然在引用环境中。我认为这叫做Closure

public void DoStuff()
{
    List<IProcess> processorsForService1 = ProcessFactory.GetProcessors();
    foreach (IProcess p in processorsForService1)
    {
        if (p.ProcessTimer != null)
        {
            p.ProcessTimer.Elapsed += (s, e) =>
            {
                p.Step_One();
                p.Step_Two();
            };
        }
    }
}

请注意以下与范围相关的规则(取自msdn):

  

以下规则适用于lambda表达式中的变量范围:

     
      
  • 在引用它的委托超出范围之前,捕获的变量不会被垃圾收集。

  •   
  • 在lambda表达式中引入的变量在外部方法中不可见。

  •   
  • lambda表达式无法直接从封闭方法中捕获ref或out参数。

  •   
  • lambda表达式中的return语句不会导致封闭方法返回。

  •   
  • lambda表达式不能包含goto语句,break语句或continue语句,其目标位于正文之外或包含匿名函数的正文中。

  •   

答案 3 :(得分:0)

使事件处理程序成为IProcess的成员并设置如下:

p.ProcessTimer.Elapsed += new ElapsedEventHandler(p.IProcess_Timer_Elapsed);

如果您想在其他地方处理事件,请让处理程序转发事件:

class IProcess
{
  public delegate void Timer_Elapsed_Handler (IProcess process, ElapsedEventArgs e);
  public event Timer_Elapsed_Handler Timer_Elapsed;

  public void IProcess_Timer_Elapsed (object sender, ElapsedEventArgs e)
  {
    if (Timer_Elapsed != null) Timer_Elapsed (this, e);
  }
}