处理可能触发多个异常的方法的异常

时间:2013-07-11 08:38:54

标签: c# exception exception-handling

我有一个使用MemoryStreamGZipStream类的API类来压缩和解压缩字符串到字节数组。

使用这两个类可能会引发许多异常,我想知道处理API抛出异常的最佳方法是什么。在这种情况下,最好用我自己的Custom Exception包装每个异常,或者最好是在调用代码中捕获每个异常?

我认为这是一个不仅限于这个特定用例的问题,而是更多关于一般异常处理最佳实践的问题。

/// <summary>
/// Compress the string using the SharpLibZip GZip compression routines
/// </summary>
/// <param name="s">String object to compress</param>
/// <returns>A GZip compressed byte array of the passed in string</returns>
/// <exception cref="Helper.Core.Compression.StringCompressionException">Throw when the compression memory stream fails </exception>
/// <exception cref="System.ArgumentNullException">Throw when string parameter is Null</exception>
/// <exception cref="System.ArgumentException">Throw when the string parameter is empty</exception>
public async Task<byte[]> CompressStringAsync(string s)
{
    if (s == null) throw new ArgumentNullException("s");
    if (string.IsNullOrWhiteSpace(s)) throw new ArgumentException("s");

    byte[] compressed = null;

    try
    {
        using (MemoryStream outStream = new MemoryStream())
        {
            using (GZipStream tinyStream = new GZipStream(outStream,CompressionMode.Compress))
            {
                using (MemoryStream memStream = new MemoryStream(Encoding.UTF8.GetBytes(s)))
                {
                    await memStream.CopyToAsync(tinyStream);
                }
            }
            compressed = outStream.ToArray();
        }
        return compressed;
    }
    catch (ArgumentNullException ex)
    {
        throw new StringCompressionException("Argument Was Null", ex);
    }
    catch (EncoderFallbackException ex)
    {
        throw new StringCompressionException("Stream Encoding Failure", ex);
    }
    catch (ArgumentException ex)
    {
        throw new StringCompressionException("Argument Was Not Valid", ex);
    }
    catch (ObjectDisposedException ex)
    {
        throw new StringCompressionException("A Stream Was Disposed", ex);
    }
    catch (NotSupportedException ex)
    {
        throw new StringCompressionException("Action Was Not Supported", ex);
    }
}

Here是关于捕获基本异常的好帖子。

3 个答案:

答案 0 :(得分:2)

您已经在您展示的示例代码中利用了Exception基类的"inner exception" functionality,那么为什么不一直采用它?

您不需要重新编写内部异常的消息,只需将异常包装在StringCompressionException类中即可。如果捕获您的异常的客户想知道有关失败的更详细信息,他们可以检查内部异常。

这使您的代码更加简单:

try
{
    using (MemoryStream outStream = new MemoryStream())
    {
        using (GZipStream tinyStream = new GZipStream(outStream,CompressionMode.Compress))
        {
            using (MemoryStream memStream = new MemoryStream(Encoding.UTF8.GetBytes(s)))
            {
                await memStream.CopyToAsync(tinyStream);
            }
        }
        compressed = outStream.ToArray();
    }
    return compressed;
}
catch (Exception ex)
{
    throw new StringCompressionException("Compressing string failed; see inner exception for details.", ex);
}

另请注意,异常消息字符串不易轻松本地化,因此它们不应该是您应该向最终用户显示的内容。它们实际上只是一个调试辅助工具,所以像#34;看到内部异常的细节&#34;工作得很好。维护程序员知道该怎么做。

答案 1 :(得分:0)

一般来说,我会这样做

try
{
    CodeThatThrowsExceptions();
}
catch(ArgumentException ae)
{
    //Recoverable, request new args
}
catch(OtherRecoverableException oe)
{
    //take appropriate action
}
catch(Exception e)
{
    //Unexpected irrecoverable error. Handle appropriately
}

这允许您在每种情况下执行相关的操作(即请求新参数)并在适当时处理/抛出。

答案 2 :(得分:0)

始终建议您在最后处理特定异常,然后处理常规异常。此外,决定取决于您计划在收到特定异常时实施的操作类型。从你的代码看,你看起来正在从所有特定的异常中引发相同的异常,所以除非你想在特定的块中采取任何特定的动作,否则我将使用带有基本异常的catch块或者只是捕获。

另外要记住的是 throw new xxx 重置堆栈跟踪,因此您可能会遗漏一些重要信息,因为生成了异常。< / p>