简体   繁体   English

异步方法异常的不同行为

[英]Different behavior of exception with async method

Supposed you have 2 async method define as bellow: 假设您有2个async方法定义如下:

public async Task<TResult> SomeMethod1()
{
    throw  new Exception();
}

public async Task<TResult> SomeMethod2()
{
    await Task.Delay(50);
    throw new Exception();
}

Now if you await on those 2 methods the behavior will be pretty much the same. 现在,如果await这两种方法,行为将基本相同。 But if you are getting the task the behavior is different. 但是,如果你正在完成任务,行为是不同的。

If I want to cache the result of such a computation but only when the task run to completion. 如果我想缓存这样的计算结果,但只有当任务运行完成时。 I have to take care of the 2 situation: 我必须照顾这两种情况:

First Situation: 第一种情况:

public Task<TResult> CachingThis1(Func<Task<TResult>> doSomthing1)
{
    try
    {
       var futur = doSomthing1()
       futur.ContinueWith(
               t =>
               {
                  // ... Add To my cache
               },
               TaskContinuationOptions.NotOnFaulted);
    }
    catch  ()
    {
        // ... Remove from the pending cache
        throw;
    }
}

Second Situation 第二种情况

public Task<TResult> CachingThis2(Func<Task<TResult>> doSomthing)
{
    var futur = SomeMethod2();
    futur.ContinueWith(
       t =>
       {
           // ... Add To my cache
       },
       TaskContinuationOptions.NotOnFaulted);
    futur.ContinueWith(
       t =>
       {
          // ... Remove from the pending cache
       },
       TaskContinuationOptions.OnlyOnFaulted);
}

Now I pass to my caching system the method that will execute the computation to cache. 现在我将执行计算缓存的方法传递给我的缓存系统。

cachingSystem.CachingThis1(SomeMethod1);
cachingSystem.CachingThis2(SomeMethod2);

Clearly I need to duplicate code in the " ConinueWith on faulted" and the catch block. 显然,我需要在“ ConinueWith on ConinueWith ”和catch块中复制代码。 Do you know if there is a way to make the exception behave the same whether it is before or after an await? 你知道是否有办法使异常行为相同,无论是在await之前还是之后?

There's no difference in the exception handling required for both SomeMethod1 and SomeMethod2 . SomeMethod1SomeMethod2所需的异常处理没有区别。 They run exactly the same way and the exception would be stored in the returned task. 它们以完全相同的方式运行,异常将存储在返回的任务中。

This can easily be seen in this example; 这个例子很容易看出来;

static void Main(string[] args)
{
    try
    {
        var task = SomeMethod1();
    }
    catch
    {
        // Unreachable code
    }
}

public static async Task SomeMethod1()
{
    throw new Exception();
}

No exception would be handled in this case since the returned task is not awaited. 在这种情况下不会处理任何异常,因为不等待返回的任务。

There is however a distinction between a simple Task -returning method and an async method: 但是,简单的Task -returning方法和async方法之间存在区别:

public static Task TaskReturning()
{
    throw new Exception();
    return Task.Delay(1000);
}

public static async Task Async()
{
    throw new Exception();
    await Task.Delay(1000);
}

You can avoid code duplication by simply having an async wrapper method that both invokes the method and await s the returned task inside a single try-catch block: 您可以通过简单地使用async包装器方法来避免代码重复,该方法既可以调用方法,也可以在单个try-catch块中await返回的任务:

public static async Task HandleAsync()
{
    try
    {
        await TaskReturning();
        // Add to cache.
    }
    catch
    {
        // handle exception from both the synchronous and asynchronous parts.
    }
}

In addition to what I3arnon said in his answer, in case you ContinueWith on async method without the TaskContinuationOptions you specify, exception captured by the Task parameter you receive in the continuation handler can be handled in the following way: 除了I3arnon在他的回答中所说的,如果您在没有指定的TaskContinuationOptions情况下ContinueWith使用异步方法,则可以通过以下方式处理在延迟处理程序中接收的Task参数捕获的异常:

SomeMethod1().ContinueWith(ProcessResult);
SomeMethod2().ContinueWith(ProcessResult);

With ProcessResult handler which looks like: 使用ProcessResult处理程序,如下所示:

private void ProcessResult<TResult>(Task<TResult> task)
{
    if (task.IsFaulted)
    {
        //remove from cahe
    }
    else if (task.IsCompleted)
    {
        //add to cache
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM