Frage Eine Ausnahme abfangen, die in einem asynchronen Callback ausgelöst wird


Ich habe eine Methode, die ein Callback-Argument asynchron ausführt, aber der catch-Block scheint keine vom synchronen Aufruf ausgelösten Ausnahmen zu fangen (this.Submit bezieht sich auf eine synchrone Methode).

public void Submit(FileInfo file, AnswerHandler callback)
{
    SubmitFileDelegate submitDelegate = new SubmitFileDelegate(this.Submit);
    submitDelegate.BeginInvoke(file, (IAsyncResult ar) =>
    {
        string result = submitDelegate.EndInvoke(ar);
        callback(result);
    }, null);
}

Gibt es eine Möglichkeit, die vom neuen Thread ausgelöste Ausnahme abzufangen und an den ursprünglichen Thread zu senden? Ist dies auch der "richtige" Weg, asynchrone Ausnahmen zu behandeln? Ich habe meinen Code so geschrieben, dass er so heißen könnte (vorausgesetzt, das Ausnahmeproblem ist behoben):

try
{
    target.Submit(file, (response) =>
    {
        // do stuff
    });
}
catch (Exception ex)
{
    // catch stuff
}

Aber gibt es einen angemesseneren oder eleganteren Weg, dies zu tun?


9
2018-01-05 19:39


Ursprung


Antworten:


Dies ist keine "Best Practice" -Lösung, aber ich denke, es ist eine einfache, die funktionieren sollte.

Anstatt den Delegaten als definiert zu haben

private delegate string SubmitFileDelegate(FileInfo file);

definiere es als

private delegate SubmitFileResult SubmitFileDelegate(FileInfo file);

und definieren Sie das SubmitFileResult wie folgt:

public class SubmitFileResult
{
    public string Result;
    public Exception Exception;
}

Dann sollte die Methode, die tatsächlich die Dateiübergabe durchführt (nicht in der Frage gezeigt) wie folgt definiert werden:

private static SubmitFileResult Submit(FileInfo file)
{
    try
    {
        var submissionResult = ComplexSubmitFileMethod();

        return new SubmitFileResult { Result = submissionResult };
    }
    catch (Exception ex)
    {
        return new SubmitFileResult {Exception = ex, Result = "ERROR"};
    }
}

Auf diese Weise untersuchen Sie das Ergebnisobjekt, prüfen, ob das Feld "Ergebnis" oder "Ausnahme" festgelegt ist, und agieren entsprechend.


8
2018-01-05 20:37



Wenn Sie auf .NET 4.0 abzielen, können Sie die neue Task Parallel Library verwenden und die Task Objekt ist Exception Eigentum.

public Task Submit(FileInfo file)
{
    return Task.Factory.StartNew(() => DoSomething(file));
}

private void DoSomething(FileInfo file)
{
    throw new Exception();
}

Dann benutze es so:

Submit(myFileInfo).ContinueWith(task =>
{
    // Check task.Exception for any exceptions.

    // Do stuff with task.Result
});

woher DoSomething ist die Methode, die Sie asynchron aufrufen möchten, und der Delegat, an den Sie übergeben werden ContinueWith ist dein Rückruf.

Weitere Informationen zur Ausnahmebehandlung in TPL finden Sie hier: http://msdn.microsoft.com/en-us/library/dd997415.aspx


9
2018-01-05 20:17



Kurz gesagt, nein.

Wenn du anrufst submitDelegate.BeginInvoke, erzeugt es den neuen Thread, kehrt zurück und beendet prompt den try / catch-Block (während der neue Thread im Hintergrund läuft).

Du könntest jedoch fangen alle unbehandelte Ausnahmen wie folgt:

AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(YourException);

Dies fängt jedoch alles in der Anwendungsdomäne auf (nicht nur Ihre asynchrone Methode).


3
2018-01-05 20:02