繁体   English   中英

异步方法异常的不同行为

[英]Different behavior of exception with async method

假设您有2个async方法定义如下:

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

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

现在,如果await这两种方法,行为将基本相同。 但是,如果你正在完成任务,行为是不同的。

如果我想缓存这样的计算结果,但只有当任务运行完成时。 我必须照顾这两种情况:

第一种情况:

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;
    }
}

第二种情况

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);
}

现在我将执行计算缓存的方法传递给我的缓存系统。

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

显然,我需要在“ ConinueWith on ConinueWith ”和catch块中复制代码。 你知道是否有办法使异常行为相同,无论是在await之前还是之后?

SomeMethod1SomeMethod2所需的异常处理没有区别。 它们以完全相同的方式运行,异常将存储在返回的任务中。

这个例子很容易看出来;

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

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

在这种情况下不会处理任何异常,因为不等待返回的任务。

但是,简单的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);
}

您可以通过简单地使用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.
    }
}

除了I3arnon在他的回答中所说的,如果您在没有指定的TaskContinuationOptions情况下ContinueWith使用异步方法,则可以通过以下方式处理在延迟处理程序中接收的Task参数捕获的异常:

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

使用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