处理异步方法的同步部分中的异常

nos*_*tio 5 .net c# exception task-parallel-library async-await

我正在处理我开始的任务可能抛出的情况,同时仍然在初始线程上同步执行.出于说明的目的,这样的事情:

static async Task TestAsync()
{
    var random = new Random(Environment.TickCount).Next();
    if (random % 2 != 0)
        throw new ApplicationException("1st");

    await Task.Delay(2000);
    Console.WriteLine("after await Task.Delay");
    throw new ApplicationException("2nd");
}
Run Code Online (Sandbox Code Playgroud)

从调用代码,我希望能够捕获任何异常,可能从同步部分抛出(即,直到await Task.Delay()).这是我目前正在做的事情:

static void Main(string[] args)
{
    try
    {
        var task = TestAsync();
        if (task.IsFaulted)
            task.GetAwaiter().GetResult();
        Console.WriteLine("TestAsync continues asynchronously...");
    }
    catch (Exception e)
    {
        Console.WriteLine("Error: " + e.ToString());
    }

    Console.WriteLine("Press Enter to exit...");
    Console.ReadLine();
}
Run Code Online (Sandbox Code Playgroud)

这工作,虽然它看起来有点拗口,因为没有ResultTask.

我也试过task.Wait()而不是task.GetAwaiter().GetResult().这总是给我AggregateException我必须打开(而不是ApplicationException直接预期).

还有其他选择吗?

[编辑]为了解决这些评论:我这样做,因为如果任务立即失败,我不想将其添加到我维护的待处理任务列表中.任务本身对这样的列表一无所知(并且它不必).我仍然想记录异常,并让用户知道它.我也可以这样做throw task.Exception,但这不会给出捕获的异常堆栈帧ExceptionDispatchInfo.

[更新]灵感来自其他答案和评论:如果我完全掌控TestAsync并且我不想引入新的班级成员,我也可以做类似下面的事情.验证参数时可能会派上用场:

static Task TestAsync(int delay)
{
    if (delay < 0)
        throw new ArgumentOutOfRangeException("delay");

    Func<Task> asyncPart = async () =>
    {
        Console.WriteLine("await Task.Delay");
        await Task.Delay(delay);
        throw new ApplicationException("2nd");
    };

    return asyncPart();
}
Run Code Online (Sandbox Code Playgroud)

Joh*_*ibb 1

我会把它分成两部分,而不是依赖它task.GetAwaiter().GetResult()来工作。我担心TestAsync将来有人维护时会无意中破坏东西。

我就是这样写的。这应该保留你所拥有的行为,但我发现发生的事情更明显:

static Task Test()
{
    var random = new Random(Environment.TickCount).Next();
    if (random % 2 != 0)
        throw new ApplicationException("1st");

    return TestAsync();
}

static async Task TestAsync()
{
    await Task.Delay(2000);
    Console.WriteLine("after await Task.Delay");
    throw new ApplicationException("2nd");
}



static void Main(string[] args)
{
    try
    {
        Test();
        Console.WriteLine("TestAsync continues asynchronously...");
    }
    catch (Exception e)
    {
        Console.WriteLine("Error: " + e.ToString());
    }

    Console.WriteLine("Press Enter to exit...");
    Console.ReadLine();
}
Run Code Online (Sandbox Code Playgroud)

  • 第二个异常永远不会被捕获,因为任务的结果不会在任何地方使用 - 因此即使“random”为 2,“Error”消息也永远不会打印到屏幕上。您需要使用 `Test().Wait()` 来抛出第二个异常(作为 `AggregateException`) (2认同)