1

我需要每 5 秒调用一次异步操作,因为有时操作可能会更长,我想出调用方法,然后在我得到结果后等待 5 秒并再次调用它。

在主要课程中,我有这样的事情:

public partial class Form1 : Form
{
    private Timer loopTimer;
    public Form1()
    {
        InitializeComponent();
        loopTimer = new Timer() { Interval = 10000 /*10 seconds*/};
        loopTimer.Tick += loopTimer_Tick;
        EWS.Instance.DoOperation(Operation_OK, Operation_ERROR);
    }

    private void Operation_OK(int count)
    {
        Console.WriteLine("timer start");
        loopTimer.Start();
        Console.WriteLine("timer enabled: " + loopTimer.Enabled);
        Console.WriteLine("async result : " + count);
    }

    private void Operation_ERROR(string err)
    {
        MessageBox.Show(err);
    }

    private void loopTimer_Tick(object sender, EventArgs e)
    {
        Console.WriteLine("tick");
        loopTimer.Stop();
        EWS.Instance.DoOperation(Operation_OK, Operation_ERROR);
    }
}

我的 EWS 课程如下所示:

class EWS : SingletonBase<EWS>
{
    private EWS()
    {
    }

    private int LongRunningMethod(Action<string> error)
    {
        Console.WriteLine("5 seconds operation");
        Thread.Sleep(5000);
        int unreadCount = 100;
        return unreadCount;
    }

    public class CommandAndCallback<TSuccess, TError>
    {
        public TSuccess Success { get; set; }
        public TError Error { get; set; }
        public Func<Action<string>, int> Delegate { get; set; }
    }

    public void DoOperation(Action<int> success, Action<string> error)
    {
        Func<Action<string>, int> dlgt = LongRunningMethod;
        CommandAndCallback<Action<int>, Action<string>> config = new CommandAndCallback<Action<int>, Action<string>>() { Success = success, Error = error, Delegate = dlgt };

        dlgt.BeginInvoke(error, MyAsyncCallback, config);
    }

    public void MyAsyncCallback(IAsyncResult ar)
    {
        int s;
        CommandAndCallback<Action<int>, Action<string>> config = (CommandAndCallback<Action<int>, Action<string>>)ar.AsyncState;
        s = config.Delegate.EndInvoke(ar);
        Console.WriteLine(s);
        if (s > -1)
            config.Success(s);
    }
}

我可以异步调用我的方法,处理错误,但我不知道为什么我无法在 5 秒后再次调用它。

loopTimer_Tick在我打电话后不叫loopTimer.Start();
我重写这几次,每次我不能让那个计时器工作。

我需要循环调用方法(调用交换服务器),但调用之间有时间中断,如果有更好的方法,请写:)

4

1 回答 1

2

The System.Windows.Forms.Timer class is not thread-safe. The specific failure here is that you call its Start() method on a thread pool thread. That creates a hidden window that provides the Tick event but its being created on the wrong thread. One that doesn't pump a message loop so the Tick event is never raised.

A possible workaround is to call Start() on the main thread, in the DoOperation() method for example. Or to use a System.Timers.Timer instead, beware however that its Elapsed event handler runs on an arbitrary threadpool thread so you cannot directly access the UI from it. You ought to do something about actually canceling the operation, this kind of code tends to get simpler if you use the BackgroundWorker or Task class.

于 2012-10-03T12:31:33.853 回答