在连续调用前等待C#方法的超时并重置计时器。

3

我在代码中有一个事件,可能在某个时刻被触发多次。

然而,我希望实现一种方法,在真正触发之前让该方法等待500毫秒,如果在这500毫秒内再次调用该方法,则重置计时器并再次等待500毫秒。

来自javascript的经验告诉我,可以使用setTimeout或setInterval实现此功能。然而,我很难想出如何在C#中实现这样的功能。

4个回答

4
您可以使用包含在类中的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"只会显示一次——第二次调用将简单地重置计时器。

0

有趣。我会深入研究。 - RVandersteen

-1

如果再次触发相同的方法,我该如何停止执行此线程? - RVandersteen
更新的答案。使用锁和睡眠。 - James Dev
不确定我的问题是否太模糊或者我漏掉了什么。但这会防止其他调用触发此代码,对吧?我想要的是,如果再次调用该方法,则将计时器重置为0。(因此忽略之前的调用) - RVandersteen
锁定会阻止任何其他线程运行锁定内的代码,直到锁定被释放。因此,一旦解除锁定,另一个线程就可以进入,在那里线程将再次睡眠500毫秒。因此,不需要将“计时器”重新设置为0。因此,实质上,调用被排队等待执行,当你说重置计时器时,是指在线程被锁定期间忽略任何调用吗? - James Dev
方便的工具,但不是我正在寻找的。我会更新我的问题。 - RVandersteen

-1

刚刚用 System.Threading.Thread 写了一个超级简单的类,使用方法有点不同。

var delayedCaller = new DelayedTimeout(() => HelloWorld(123), 500, false);
delayedCaller.ResetTimer();
delayedCaller.ResetTimer();

目前,您可以使用以下类非常简单地完成它

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
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接