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

System.Windows.Forms.Timer クラスはスレッド セーフではありません。ここでの具体的な失敗は、スレッド プール スレッドでその Start() メソッドを呼び出したことです。これにより、Tick イベントを提供する非表示のウィンドウが作成されますが、間違ったスレッドで作成されます。メッセージ ループをポンピングしないため、Tick イベントが発生することはありません。

考えられる回避策は、たとえば DoOperation() メソッドで、メイン スレッドで Start() を呼び出すことです。または代わりに System.Timers.Timer を使用するには、その Elapsed イベント ハンドラーが任意のスレッドプール スレッドで実行されるため、そこから UI に直接アクセスできないことに注意してください。実際に操作をキャンセルするには、何かを行う必要があります。BackgroundWorker または Task クラスを使用すると、この種のコードはより単純になる傾向があります。

于 2012-10-03T12:31:33.853 に答える