2

私のコンソールアプリはSystem.ComponentModel.BackgroundWorkerスレッド化の目的で使用します:

System.ComponentModel.BackgroundWorker backgroundWorker = new System.ComponentModel.BackgroundWorker();

backgroundWorker.DoWork += (sender, e) =>
     ReportStatus(worker, status, result, e);
backgroundWorker.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);
backgroundWorker.RunWorkerAsync(worker);

ご覧のとおり、RunWorkerAsync内で引数として「worker」を渡しています。

私が達成しようとしているのは、ReportStatusメソッド内に例外がある場合、何らかの操作を実行できるように同じ「ワーカー」オブジェクトが必要なことです(サービスを呼び出してそのワーカーの例外を通知します)

private void ReportStatus(Worker worker, Status status, WorkResult result,System.ComponentModel.DoWorkEventArgs arg)
{
    var proxy = new PreparationServiceProxy(new NetTcpBinding(), new EndpointAddress(PreparationEngineState.ServiceAddress));
    try
    {
        proxy.ReportStatus(worker, status, result);
        proxy.Close();
    }
    catch (Exception)
    {
        arg.Result = worker;
        proxy.Abort();
        throw;
    }
}

私の例外ブロックでは(これが正しい方法かどうかはわかりません!)RunWorkerCompletedメソッド(backgroundWorker1_RunWorkerCompleted)が実行されたときに同じワーカーを取り戻すことができるように、ワーカーをResultに割り当てています:

private void backgroundWorker1_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
{

    if (e.Error != null)
    {
        Worker worker = e.Result as Worker; // At this point I get an exception!
    }
}
4

3 に答える 3

2

例外を再スローしたためです。 BackgroundWorkerハンドラーによって処理されない例外としてそれを認識しDoWork、値を取得したときに他のスレッドに再スローしResultます。

それを望まない場合は、ハンドラーthrowのキャッチを削除してください。DoWork

ワーカーオブジェクトをに渡した場合は、テストするブロックへの呼び出しまたはブロック内BackgroundWorkerの呼び出しをラップする例外ハンドラーで渡したものだけを使用しないのはなぜですか?例えば:ResultError

        if (e.Error != null)
        {
            worker.DoSomething(); // no access of Result
        }
于 2012-09-12T20:54:02.890 に答える
2

.NETは、エラーが発生した場合に非同期操作が何らかの結果をもたらす可能性があるとは見なしません。そういうわけであなたはそれを他の方法で渡すでしょう。

カスタム例外クラスを実装することをお勧めします。

public class WorkerException:ApplicationException
{
    public WorkerException(Worker worker,Exception innerException):base(null,innerException)
    { Worker = worker; }

    public Worker Worker
    {
        get;
        set;
    }
}

それに応じて例外をラップします。

private void ReportStatus(Worker worker, Status status, WorkResult result,System.ComponentModel.DoWorkEventArgs arg)
{
    var proxy = new PreparationServiceProxy(new NetTcpBinding(), new EndpointAddress(PreparationEngineState.ServiceAddress));
    try
    {
        proxy.ReportStatus(worker, status, result);
        proxy.Close();
    }
    catch (Exception exception)
    {
        arg.Result = worker;
        proxy.Abort();
        throw new WorkerException(worker,exception);
    }
}

この場合、例外のワーカーを取得して、ErrorをWorkerExceptionにキャストできます。

private void backgroundWorker1_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
{

    if (e.Error is WorkerException)
    {
        Worker worker = ((WorkerException)e.Error).Worker; // At this point I get an exception!
    }
}
于 2012-09-12T22:16:32.163 に答える
0

には、メソッドに渡したのと同じオブジェクトへの参照である必要があるプロパティが含まRunWorkerCompletedEventArgsれています。(これもプロパティとしてに含まれている必要があります。)UserStateRunWorkerAsyncDoWorkEventArgsArgument

UserStateこれが正しいオブジェクト(キャスト)であり、ハンドラーが例外をスローas Workerした場合でも有効であることを確認するために実験する必要がありますが、それがあなたが探しているものかもしれないと思います。DoWork

于 2012-09-13T01:11:06.653 に答える