我有一个编程问题,我认为这是由于我在使用事件和代表时的生锈...
我有代码:
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的空引用异常。
如何在此实例中将参数传递给处理程序?
答案 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);
}
}