问题描述
在N秒之后,我正在使用以下代码来调用方法B.如果方法A在N秒超时内再次被调用,我必须将计时重新设置为N秒.
I'm using following code to call Method B after N seconds method A is called. If method Ais called again within the N seconds timeout, i have to reset the time counting back to N seconds.
我无法在项目中引用System.Windows.Form,因此无法使用System.Windows.Form.Timer.
I cannot reference System.Windows.Form in my project, so I cannot use System.Windows.Form.Timer.
方法B必须在调用线程A的同一线程中调用.
The method B must be called in the same thread A is called.
private void InitTimer()
{
timer = new BackgroundWorker();
timer.WorkerSupportsCancellation = true;
timer.WorkerReportsProgress = true;
timer.DoWork += delegate(object sender, DoWorkEventArgs e)
{
var st = DateTime.Now;
while (DateTime.Now.Subtract(st).TotalSeconds < 10)
{
if (timer.CancellationPending)
{
e.Cancel = true;
return;
}
}
};
timer.RunWorkerCompleted += delegate(object sender, RunWorkerCompletedEventArgs e)
{
if (!e.Cancelled)
{
MethodB();
}
else
{
timer.RunWorkerAsync();
}
};
}
public void MethodA()
{
if (timer.IsBusy)
timer.CancelAsync();
else
timer.RunWorkerAsync();
}
public void MethodB()
{
//do some stuff
}
实际上,代码可以工作,但是我认为这有点令人困惑.您知道是否有最佳实践来达到相同的结果?
Actually the code work, but i think it's a bit confounding. Do you know if there is a best practices to achieve the same result?
推荐答案
您陷入.NET 2.0实在可惜,因为 Rx扩展具有 Throttle
方法,可以非常完美地实现此效果.
It's a shame you're stuck on .NET 2.0, because Rx extensions has a Throttle
method that achieves this effect quite elegantly.
悲伤的Rx至少需要.NET 3.5 SP1.
Sadly Rx requires at least .NET 3.5 SP1.
哦,好吧!您始终可以使用 System.Threading.Timer
即可完成此操作.可以通过利用当前的 SynchronizationContext
(这是 BackgroundWorker
所做的事情)来提供同步.
Oh well! You can always use a System.Threading.Timer
to get this done instead. Synchronization can be provided by leveraging the current SynchronizationContext
(this is what BackgroundWorker
does).
这是 LaggedMethodPair
类的示意图,以说明此方法.该类在其构造函数中接受三个输入:一个将按需执行的 Action
,另一个将充当回调的 Action
,当给定的超时时间过去时,该回调将被调用,当然还有超时本身:
Here's a sketch of a LaggedMethodPair
class to illustrate this approach. The class takes three inputs in its constructor: an Action
to be performed on-demand, another Action
to serve as the callback that will be invoked when a given timeout has elapsed, and, of course, the timeout itself:
public sealed class LaggedMethodPair
{
private SynchronizationContext _context;
private Timer _timer;
private Action _primaryAction;
private Action _laggedCallback;
private int _millisecondsLag;
public LaggedMethodPair(Action primaryAction,
Action laggedCallback,
int millisecondsLag)
{
if (millisecondsLag < 0)
{
throw new ArgumentOutOfRangeException("Lag cannot be negative.");
}
// Do nothing by default.
_primaryAction = primaryAction ?? new Action(() => { });
// Do nothing by default.
_laggedCallback = laggedCallback ?? new Action(() => { });
_millisecondsLag = millisecondsLag;
_timer = new Timer(state => RunTimer());
}
public void Invoke()
{
// Technically there is a race condition here.
// It could be addressed, but in practice it will
// generally not matter as long as Invoke is always
// being called from the same SynchronizationContext.
if (SynchronizationContext.Current == null)
{
SynchronizationContext.SetSynchronizationContext(
new SynchronizationContext()
);
}
_context = SynchronizationContext.Current;
ResetTimer();
_primaryAction();
}
void ResetTimer()
{
_timer.Change(_millisecondsLag, Timeout.Infinite);
}
void RunTimer()
{
_context.Post(state => _laggedCallback(), null);
}
}
我编写了一个示例Windows Forms应用程序来演示此类.该表单包含一个 LaggedMethodPair
成员,其超时时间为2000毫秒.它的 primaryAction
将一个项目添加到列表视图.其 laggedCallback
将高亮显示的项目添加到列表视图中.
I wrote a sample Windows Forms app to show this class in action. The form contains a LaggedMethodPair
member with a timeout of 2000 ms. Its primaryAction
adds an item to a list view. Its laggedCallback
adds a highlighted item to the list view.
您可以看到代码按预期运行.
You can see that the code runs as expected.
这篇关于如果方法A的调用时间不超过N秒,则调用方法B的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!