异步方法异常的不同行为

时间:2014-11-24 13:55:06

标签: c# .net exception-handling task-parallel-library async-await

假设你有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 faulted”和catch块中复制代码。 你是否知道是否有办法让异常在await之前或之后表现相同?

2 个答案:

答案 0 :(得分:3)

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

这个例子很容易看出来;

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

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

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

然而,简单的Task - 返回方法与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包装器方法来避免代码重复,该方法既调用方法又await在单个try-catch块中返回任务:

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

答案 1 :(得分:0)

除了I3arnon在他的回答中所说的,如果你在{em> async 方法ContinueWith没有指定TaskContinuationOptions的情况下,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
    }
}