我正在system.Timers.Timer用来创建一个计时器.
public System.Timers.Timer timer = new System.Timers.Timer(200);
private void btnAutoSend_Click(object sender, EventArgs e)
{
timer.Enabled = true;
timer.Elapsed += new System.Timers.ElapsedEventHandler(send);
timer.AutoReset = true;
}
public void send(object source, System.Timers.ElapsedEventArgs e)
{
this.rtbMsg.AppendText("psyche-->" + receiver + ": hello\n");
}
Run Code Online (Sandbox Code Playgroud)
发送函数中的接收器是我在使用函数时需要设置的参数,但是当我在发送函数中添加参数时,如:
public void send(object source, System.Timers.ElapsedEventArgs e,string receiver)
Run Code Online (Sandbox Code Playgroud)
然后它会抛出一个错误.在检查了MSDN之后,它说ElapsedEventArgs仅适用于这些不会产生数据的函数.
我怎么解决这个问题?我的程序不是windows.Form,所以我不能使用System.Windows.Forms.Timer.
Cam*_*ron 21
你不能将额外的参数传递给事件处理程序回调,因为你不是那个调用它的人 - Timer是; 这就是重点;-)
但是,使用闭包可以轻松实现相同的效果:
private void btnAutoSend_Click(object sender, EventArgs e)
{
timer.Elapsed += (timerSender, timerEvent) => send(timerSender, timerEvent, receiver);
timer.AutoReset = true;
timer.Enabled = true;
}
public void send(object source, System.Timers.ElapsedEventArgs e, string receiver)
{
this.rtbMsg.AppendText("psyche-->" + receiver + ": hello\n");
}
Run Code Online (Sandbox Code Playgroud)
现在,Elapsed处理程序是(timerSender, timerEvent) =>lambda操作,它关闭receiver变量并send在每次触发lambda时使用extra参数手动调用.
在您的特定情况下,您根本不需要发件人或参数,因此无需转发它们.代码变成:
private void btnAutoSend_Click(object sender, EventArgs e)
{
timer.Elapsed += (s_, e_) => OnTimerElapsed(receiver);
timer.AutoReset = true;
timer.Enabled = true;
}
private void OnTimerElapsed(string receiver)
{
this.rtbMsg.AppendText("psyche-->" + receiver + ": hello\n");
}
Run Code Online (Sandbox Code Playgroud)
如果你想知道所有这些的开销,它是非常小的.Lambdas只是语法糖,并且是幕后的简单函数(为事件提供了一些自动委托包装).瓶盖使用编译器生成的类实现,但你不会注意到任何代码膨胀,除非你真的有吨他们.
正如在评论中指出,你似乎是在访问的UI元素OnTimerElapsed代码-因为你不使用Windows窗体计时器,有一个很好的机会,你会通过,因为该代码将运行在这样得到一个异常计时器在触发事件时碰巧运行的任何线程 - 并且必须仅从创建它们的线程访问Windows中的UI控件.
您可以this.Invoke手动修复它,但更容易让计时器通过SynchronizingObject属性将事件编组到正确的线程:
private void btnAutoSend_Click(object sender, EventArgs e)
{
timer.SynchronizingObject = this; // Assumes `this` implements ISynchronizeInvoke
timer.Elapsed += (s_, e_) => OnTimerElapsed(receiver);
timer.AutoReset = true;
timer.Enabled = true;
}
Run Code Online (Sandbox Code Playgroud)
最后,在另一条评论的提示下,这是另一种可以存储对闭包的引用的方法,以便您以后可以取消订阅该事件:
private void btnAutoSend_Click(object sender, EventArgs e)
{
timer.SynchronizingObject = this; // Assumes `this` implements ISynchronizeInvoke
ElapsedEventHandler onElapsed;
onElapsed = (s_, e_) => {
timer.Elapsed -= onElapsed; // Clean up after firing
OnTimerElapsed(receiver);
};
timer.Elapsed += onElapsed;
timer.AutoReset = true;
timer.Enabled = true;
}
Run Code Online (Sandbox Code Playgroud)