簡體   English   中英

如何訪問計時器附帶的對象?

[英]How do I get access to the object which the Timer is attached to?

我有一個編程問題,我認為這是由於我在使用事件和委托時的生銹而引起的...

我有代碼:

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的空引用異常。

在這種情況下,如何將參數傳遞給處理程序?

看起來您正在使用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)啟動計時器。

發送者是計時器對象,而不是與處理委托關聯的對象。 首先,事件可以具有多個處理程序。

您可以做的是創建一個可以使用變量捕獲訪問IProcess的委托。

如果使用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語句,其目標位於包含的匿名函數的主體之外或主體中。

使事件處理程序成為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);
  }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM