0

私は、「重い」作業を行ういくつかの機能を持つ基本的な Windows フォーム アプリケーションに取り組んでいます。このため、バックグラウンド ワーカーの助けを借りて ThreadAbortExceptions を使用します。

public class AbortableBackgroundWorker : BackgroundWorker

-実行中の機能をキャンセルします。これらの関数を「HeavyFunction()」と呼びましょう

しかし、HeavyFunction() 内で ThreadAbortException がキャッチされたので、HeavyFunction() を呼び出した "MainForm.cs" クラスに戻る必要があります。これは、開いている他の接続 (ライターなど) を正しく閉じて、ユーザーにメッセージを表示するためです。そのため、HeavyFunction() から例外をスローし、それを MainForm でキャッチします (これは HeavyFunction() の内部にあります)。

catch (ThreadAbortException tae)
            {
                //Deligate abortion upwards.
                SomeWriter.DeleteAndClose();
                throw new ArgumentException("relevant message or identifier for later use here");
                //close and delete
            }

スローされた例外は、MainForm 内の "DoWork" 関数でキャッチされ、それに応じて処理されます。

私の質問- これは悪い習慣ですか?

私は Threads と Thread.Abort にあまり慣れていません (したがって、そもそもバックグラウンドワーカーです)

サブ質問- 呼び出されたクラス内からフォームに応答をバブルバックするためのシンプルでエレガントなソリューションは何ですか?

4

2 に答える 2

1

これは悪い習慣ですか?

はい、ThreadAbortException一般的に悪い習慣です。

TAEIMO、多くの人が操作を停止する合法的な方法と見なしているため、MSがこの例外を発明しなければ、はるかに良いでしょう。

そのため、HeavyFunction() から例外をスローするだけ
です

TPL を再発明したところOperationCancelledExceptionです。
シンプルで洗練されたソリューションは、TPL とその適切なキャンセル パターンを使用することです。

          var cts = new CancellationTokenSource();

          Task
            .Factory
            .StartNew(() => 
             { 
                 /* HeavyFunction */ 
                 while (someCondition)
                 {
                    cts.Token.ThrowIfCancellationRequested();

                    /*  do something */
                 }
             }, cts.Token);

キャンセルされたときにのみいくつかのアクションを実行したい場合はHeavyFunction、 の後に継続を追加しStartNewます。

.StartNew(/*  */)
.ContinueWith(() => {/* some action */}, TaskContinuationOptions.OnlyOnCanceled);
于 2013-09-17T10:43:54.123 に答える
0

BackgroundWorker はキャンセル シナリオをサポートします。

UI スレッドは bw.CancelAsync() を呼び出す必要がありますが、DoWork 内部では bw.CancellationPending プロパティを確認する必要があります。true の場合は DoWork を終了する必要があります。

private void buttonCancel_Click(object sender, RoutedEventArgs e)
{
if (bw.WorkerSupportsCancellation == true)
{
    bw.CancelAsync();
}
}
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;

for (int i = 1; (i <= 10); i++)
{
    if ((worker.CancellationPending == true))
    {
        e.Cancel = true;
        break;
    }
    else
    {
        // Do something heavy
    }
}
}
于 2013-09-17T10:48:41.723 に答える