C# 在调用方法之前等待超时并在连续调用时重置计时器
C# wait timeout before calling method and reset timer on consecutive calls
我的代码中有一个事件可能在某个时刻每秒触发多次。
但是我想实现一种方法让该方法在真正触发之前等待 500 毫秒,如果在这 500 毫秒结束之前再次调用该方法,请重置计时器并再次等待 500 毫秒。
来自 javascript 我知道这可以通过 setTimeout 或 setInterval 实现。但是我无法弄清楚如何在 C# 中实现这样的东西。
您可以使用带锁定的 Thread.Sleep()
private object locking = new object();
lock (locking )
{
Thread.Sleep(500);
//Your code to run here
}
https://msdn.microsoft.com/en-us/library/system.threading.thread.sleep(v=vs.110).aspx
如果再次调用该方法时需要重置定时器,可以考虑查看ManualResetEvent class:
https://msdn.microsoft.com/en-us/library/system.threading.manualresetevent(v=vs.110).aspx
您可以使用它来通知一个或多个等待线程事件已发生。
您可以使用包裹在 class 中的 System.Timers.Timer
来获得您需要的行为:
public class DelayedMethodCaller
{
int _delay;
Timer _timer = new Timer();
public DelayedMethodCaller(int delay)
{
_delay = delay;
}
public void CallMethod(Action action)
{
if (!_timer.Enabled)
{
_timer = new Timer(_delay)
{
AutoReset = false
};
_timer.Elapsed += (object sender, ElapsedEventArgs e) =>
{
action();
};
_timer.Start();
}
else
{
_timer.Stop();
_timer.Start();
}
}
}
然后可以按以下方式使用它:
public class Program
{
static void HelloWorld(int i)
{
Console.WriteLine("Hello World! " + i);
}
public static void Main(string[] args)
{
DelayedMethodCaller methodCaller = new DelayedMethodCaller(500);
methodCaller.CallMethod(() => HelloWorld(123));
methodCaller.CallMethod(() => HelloWorld(123));
while (true)
;
}
}
如果您 运行 这个例子,您会注意到 "Hello World! 123" 只显示一次 - 第二次调用只是重置计时器。
写的超级简单 class 和 System.Threading.Thread;使用稍微不同的方法。
var delayedCaller = new DelayedTimeout(() => HelloWorld(123), 500, false);
delayedCaller.ResetTimer();
delayedCaller.ResetTimer();
目前,您可以通过以下方式非常简单地做到这一点 class
public class DelayedTimeout
{
readonly Timer _timer;
readonly int _timeoutMs;
public DelayedTimeout(TimerCallback callback, int timeoutMs, bool startNow)
{
_timeoutMs = timeoutMs;
// Should we start now
var currentTimeoutMs = startNow ? _timeoutMs : Timeout.Infinite;
_timer = new Timer(callback, null, currentTimeoutMs, Timeout.Infinite);
}
// Constructor overloading
public DelayedTimeout(Action callback, int timeoutMs, bool startNow) :
this(delegate (object? obj) { callback.Invoke(); }, timeoutMs, startNow)
{}
public void ResetTimer()
{
_timer.Change(Timeout.Infinite, Timeout.Infinite); // Stop the timer
_timer.Change(_timeoutMs, Timeout.Infinite); // Stop the timer
}
}
我的代码中有一个事件可能在某个时刻每秒触发多次。
但是我想实现一种方法让该方法在真正触发之前等待 500 毫秒,如果在这 500 毫秒结束之前再次调用该方法,请重置计时器并再次等待 500 毫秒。
来自 javascript 我知道这可以通过 setTimeout 或 setInterval 实现。但是我无法弄清楚如何在 C# 中实现这样的东西。
您可以使用带锁定的 Thread.Sleep()
private object locking = new object();
lock (locking )
{
Thread.Sleep(500);
//Your code to run here
}
https://msdn.microsoft.com/en-us/library/system.threading.thread.sleep(v=vs.110).aspx
如果再次调用该方法时需要重置定时器,可以考虑查看ManualResetEvent class:
https://msdn.microsoft.com/en-us/library/system.threading.manualresetevent(v=vs.110).aspx
您可以使用它来通知一个或多个等待线程事件已发生。
您可以使用包裹在 class 中的 System.Timers.Timer
来获得您需要的行为:
public class DelayedMethodCaller
{
int _delay;
Timer _timer = new Timer();
public DelayedMethodCaller(int delay)
{
_delay = delay;
}
public void CallMethod(Action action)
{
if (!_timer.Enabled)
{
_timer = new Timer(_delay)
{
AutoReset = false
};
_timer.Elapsed += (object sender, ElapsedEventArgs e) =>
{
action();
};
_timer.Start();
}
else
{
_timer.Stop();
_timer.Start();
}
}
}
然后可以按以下方式使用它:
public class Program
{
static void HelloWorld(int i)
{
Console.WriteLine("Hello World! " + i);
}
public static void Main(string[] args)
{
DelayedMethodCaller methodCaller = new DelayedMethodCaller(500);
methodCaller.CallMethod(() => HelloWorld(123));
methodCaller.CallMethod(() => HelloWorld(123));
while (true)
;
}
}
如果您 运行 这个例子,您会注意到 "Hello World! 123" 只显示一次 - 第二次调用只是重置计时器。
写的超级简单 class 和 System.Threading.Thread;使用稍微不同的方法。
var delayedCaller = new DelayedTimeout(() => HelloWorld(123), 500, false);
delayedCaller.ResetTimer();
delayedCaller.ResetTimer();
目前,您可以通过以下方式非常简单地做到这一点 class
public class DelayedTimeout
{
readonly Timer _timer;
readonly int _timeoutMs;
public DelayedTimeout(TimerCallback callback, int timeoutMs, bool startNow)
{
_timeoutMs = timeoutMs;
// Should we start now
var currentTimeoutMs = startNow ? _timeoutMs : Timeout.Infinite;
_timer = new Timer(callback, null, currentTimeoutMs, Timeout.Infinite);
}
// Constructor overloading
public DelayedTimeout(Action callback, int timeoutMs, bool startNow) :
this(delegate (object? obj) { callback.Invoke(); }, timeoutMs, startNow)
{}
public void ResetTimer()
{
_timer.Change(Timeout.Infinite, Timeout.Infinite); // Stop the timer
_timer.Change(_timeoutMs, Timeout.Infinite); // Stop the timer
}
}