2

我有一个 API 类,它使用MemoryStreamGZipStream类将字符串压缩和解压缩为字节数组。

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

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

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

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

4

3 回答 3

2

您已经在展示的示例代码中利用了基类的“内部异常”功能Exception,那么为什么不一直使用它呢?

您不需要重新编写内部异常的消息,您只需将异常包装在您的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);
}

另请记住,异常消息字符串不容易本地化,因此无论如何它们都不应该显示给最终用户。它们实际上只是一个调试辅助工具,所以像“查看内部异常以获取详细信息”之类的东西就可以了。维护程序员知道该怎么做。

于 2013-07-11T08:43:09.503 回答
0

通常我会这样做

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

这使您可以在每种情况下执行相关操作(即请求新参数)并酌情处理/抛出。

于 2013-07-11T09:08:46.583 回答
0

始终建议您处理特定异常,然后在最后处理一般异常。此外,该决定取决于您在收到特定异常时计划实施的操作类型。从您的代码来看,您正在从所有特定异常中引发相同的异常,因此除非您想在该特定块中采取任何特定操作,否则我将在具有基本异常的 catch 块上使用或简单地捕获。

另外要记住的是throw new xxx会重置堆栈跟踪,因此您可能会从那里错过一些重要信息,即异常已生成。

于 2013-07-11T10:27:48.063 回答