2011-10-03 4 views
1

У меня есть проблема программирования, который я думаю, вызван моей ржавостью при помощи событий и делегатов ...Как получить доступ к объекту, к которому привязан таймер?

У меня есть код:

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 в первой строке.

Как передать аргумент обработчику в этом экземпляре?

+2

Это не работает. Объект не знает, к какому классу он принадлежит. Отправитель - это «Таймер», а не «IProcess» –

+0

. Так как я могу передать p обработчику событий? Мне нужно вызвать что-то в каждом классе IProcess каждые 5000 миллисекунд. – Exitos

+1

Почему каждый процесс не может прослушивать собственный таймер? –

ответ

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) пнуть таймера.

0

Отправитель - это объект таймера, а не объект, связанный с делегатом обработки. Для начала события могут иметь несколько обработчиков.

Что вы можете сделать, это создать делегат, который имеет доступ к IProcess с использованием захвата переменной.

0

Если вы использовали лямбда вместо делегата, вы можете обратиться к классу из лямбды, потому что он все равно будет в среде ссылок. Я думаю, что это называется 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):

Следующих правил применяются к области видимости переменной в лямбда-выражениях:

  • переменные, которая захватывается не будет собирать мусор, пока делегат, который ссылается на него, не выходит за рамки.

  • Переменные, введенные в выражении лямбда, не видны во внешнем методе.

  • Выражение лямбда не может непосредственно фиксировать параметр ref или out из метода размещения.

  • Оператор возврата в выражении лямбда не вызывает возвращаемого метода.

  • Выражение лямбда не может содержать оператор goto, оператор break или оператор continue, цель которого находится вне тела или в теле содержащейся анонимной функции.

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); 
    } 
} 
Смежные вопросы