3

给定一个实现如下:

public class SomeServiceWrapper
{
    public string GetSomeString()
    {
        try
        {
            //Do Something
        }
        catch (IOException e)
        {
            throw new ServiceWrapperException("Some Context", e);
        }
        catch (WebException e)
        {
            throw new ServiceWrapperException("Some Context", e);
        }
    }
}

上面的目的是让消费者GetSomeString只需要抓到ServiceWrapperException

考虑以下使用类似异步行为扩展它的方法:

public Task<string> GetSomeStringAsync()
{
    Task<string>.Factory doSomething = ...
    return doSomething.ContinueWith(x => 
    {
        if (x.IsFaulted)
        {
             if (x.Exception.InnerExceptions.Count() > 1)
             {
                 throw new AggregateException(x.Exception);
             }

             var firstException = x.Exception.InnerExceptions[0];
             if (typeof(firstException) == typeof(IOException)
                 || typeof(firstException) == typeof(WebException))
             {
                 throw new ServiceWrapperException("Some Context", firstException);
             }
        }

        return x.Result;
    }
} 

这种包装异常的同步方法自然不适合异步方法。

作者可以SomeServiceWrapper做些什么来简化任何消费者的异常处理代码,以便他们只需要处理TradeLoaderException而不是同时处理IOExceptionand WebException

4

1 回答 1

2

我做了一个几乎可以做到这一点的扩展方法。用法:

public static Task<string> GetSomeStringAsync()
{
    var doSomething = Task.Factory.StartNew(() => "bar");
    return doSomething.WrapExceptions(typeof(IOException), typeof(WebException));
}
  1. 您可以继续返回原始任务。
  2. 我建议更改 ServiceWrapperException 以保存多个异常,例如 AggregateException,然后更改第一部分。

方法:

public static Task<TResult> WrapExceptions<TResult>(this Task<TResult> task, params Type[] exceptionTypes)
{
    return task.ContinueWith(_ =>
    {
        if (_.Status == TaskStatus.RanToCompletion) return _.Result;

        if (_.Exception.InnerExceptions.Count > 1)
        {
            throw new AggregateException(_.Exception);
        }

        var innerException = _.Exception.InnerExceptions[0];
        if (exceptionTypes.Contains(innerException.GetType()))
        {
            throw new ServiceWrapperException("Some Context", innerException);
        }

        throw _.Exception;
    });
}
于 2013-11-22T19:26:49.650 回答