代码之家  ›  专栏  ›  技术社区  ›  Andrea Parodi

如果方法A未被调用超过N秒,则调用方法B

  •  0
  • Andrea Parodi  · 技术社区  · 16 年前

    我使用下面的代码在方法A被调用N秒后调用方法B。如果方法A 在N秒超时内再次调用时,我必须将时间倒数重置为N秒。

    我不能引用系统.Windows.Form在我的项目中,所以我不能使用系统.Windows.Form.计时器。

    方法B必须在调用A的同一线程中调用。

    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
    
    }
    

    实际上代码是有效的,但我觉得有点混乱。你知道是否有一个最佳实践来达到同样的效果吗?

    3 回复  |  直到 16 年前
        1
  •  4
  •   Dan Tao    16 年前

    很遗憾你被困在.NET2.0上,因为 Rx extensions 有一个 Throttle

    很遗憾,Rx至少需要.NET 3.5 SP1。

    哦,好吧!你可以随时使用 System.Threading.Timer 来完成这件事。同步可以通过利用当前 SynchronizationContext (这是什么 BackgroundWorker 是的)。

    这是一幅 LaggedMethodPair Action 按需执行,另一个 行动 当给定的超时已经过去时,作为将被调用的回调,当然还有超时本身:

    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窗体应用程序来演示这个类的实际操作。表单包含 滞后方法 成员的超时时间为2000毫秒 primaryAction 将项目添加到列表视图。它 laggedCallback 将突出显示的项添加到列表视图。

    LaggedMethodPair Test Form

        2
  •  1
  •   Adrian Grigore    16 年前

    我将把这个功能封装到一个计时器类中,其中包含其他类可以订阅的事件(例如计时器.tick事件)。

        3
  •  0
  •   tia    16 年前

    我想用 AutoResetEvent ,因为它能够等待信号。我使用它让worker等待来自A()的信号,如果时间过长,将调用B()。

    class Caller
    {
        AutoResetEvent ev = new AutoResetEvent(false);
        public void A()
        {
            ev.Set();
            // do your stuff
            Console.Out.WriteLine("A---");
        }
        void B()
        {
            Console.Out.WriteLine("B---");
        }
    
        public void Start()
        {
            var checker = new BackgroundWorker();
            checker.DoWork += new DoWorkEventHandler(checker_DoWork);
            checker.RunWorkerAsync();
        }
    
        void checker_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = sender as BackgroundWorker;
            while (!worker.CancellationPending)
            {
                bool called = ev.WaitOne(TimeSpan.FromSeconds(3));
                if (!called) B();
            }
        }
    }
    

    推荐文章