简体   繁体   English

在重写同步代码以使用TPL时如何简化或包装异常

[英]How to simplify or wrap exceptions when rewriting synchronous code to use TPL

Given an implementation as follows: 鉴于实施如下:

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

The intention of the above is to enable the consumer of GetSomeString to only need to catch ServiceWrapperException . 上述目的是使GetSomeString的使用者只需要捕获ServiceWrapperException

Consider the following approach to extending this with a similar async behaviour: 请考虑以下方法以使用类似的异步行为来扩展它:

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

This synchronous approach to wrapping exceptions doesn't fit naturally with the asynchronous approach. 这种包装异常的同步方法自然不适合异步方法。

What could the author of SomeServiceWrapper do to simplify the exception handling code of any consumers so they only need to handle TradeLoaderException instead of both IOException and WebException ? SomeServiceWrapper的作者可以做些什么来简化任何消费者的异常处理代码,这样他们只需要处理TradeLoaderException而不是IOExceptionWebException

I made an extension method that pretty much does that. 我做了一个扩展方法,几乎​​就是这样。 Usage: 用法:

public static Task<string> GetSomeStringAsync()
{
    var doSomething = Task.Factory.StartNew(() => "bar");
    return doSomething.WrapExceptions(typeof(IOException), typeof(WebException));
}
  1. You can just return the original task with the continuation. 您可以使用延续返回原始任务。
  2. I would suggest changing ServiceWrapperException to hold more than one exception like AggregateException and then change the first part. 我建议更改ServiceWrapperException以保存多个异常,如AggregateException,然后更改第一部分。

The Method: 方法:

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

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

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