我应该捕获所有可能的特定异常或只是一般的异常并将其包装在自定义异常中吗? [英] Should I catch all possible specific exceptions or just general Exception and wrap it in custom one?

查看:176
本文介绍了我应该捕获所有可能的特定异常或只是一般的异常并将其包装在自定义异常中吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我想将一些XML文件反序列化为一个强类型的对象。如果这个XML文件不能反序列化(无论什么原因),我将创建一个默认对象,并继续正常的应用程序工作流,而不会向用户显示任何错误。 (实际上这个应用程序是作为Windows服务运行的,所以没有用户为它...例如,想象应用程序尝试加载配置文件,如果失败,那么只需使用默认配置)。



我的问题是如何创建Deserialize()方法,以便通过调用代码易于使用?我的主要关注点是如何处理异常...这是我的研究。



解决方案1:



这里是最简单的方法:

  public static T Deserialize< T>(string xml)
{
var serializer = new XmlSerializer(typeof(T));
使用(var sr = new StreamReader(xml))
使用(var reader = XmlReader.Create(sr))
return(T)serializer.Deserialize(reader);
}

我认为这种方法的使用在调用代码中会很难,因为我'必须处理任何这些方法/构造函数抛出的所有可能的异常。调用代码不在意,只关心操作是否成功。



所以这是我的第二个尝试:



解决方案2:

  public static T Deserialize< T>(string xml) 
{
try
{
var serializer = new XmlSerializer(typeof(T));
使用(var sr = new StreamReader(xml))
使用(var reader = XmlReader.Create(sr))
return(T)serializer.Deserialize(reader);
}
catch(ArgumentException ex)
{
throw new XmlDeserializeException(ValidationExceptionMsg,ex);
}
catch(IOException ex)
{
throw new XmlDeserializeException(ValidationExceptionMsg,ex);
}
catch(XmlSchemaException ex)
{
throw new XmlDeserializeException(ValidationExceptionMsg,ex);
}
catch(InvalidOperationException ex)
{
throw new XmlDeserializeException(ValidationExceptionMsg,ex);
}
}

这里我创建了一个名为XmlDeserializeException的自定义异常,并使用它将包装try块中可能抛出的所有异常(在MSDN中指定)。现在,调用代码只能捕获XmlDeserializeException来知道有错误。但是我不知道这个解决方案有多好...如果我需要创建很多这样的方法,那么所有这些方法都会有很多catch块,只能将异常包装到自定义异常中。



所以我想知道以下代码是否更好:



解决方案3:

  public static T Deserialize< T>(string xml)
{
try
{
var serializer = new XmlSerializer(typeof(T));
使用(var sr = new StreamReader(xml))
使用(var reader = XmlReader.Create(sr))
return(T)serializer.Deserialize(reader);
}
catch(Exception ex)
{
throw new XmlDeserializeException(ValidationExceptionMsg,ex);
}
}

这里我捕获一般异常并将其包装在自定义XmlDeserializeException 。这样我就减少了代码写入,没有代码冗余,而且不那么杂乱。调用代码将再次只需要解决方案2中的XmlDeserializeException。



我应该使用哪个解决方案,为什么?有没有更好的方法?请记住我想使用这个Deserialize()方法的场景,这不是一个库/框架,而是一个没有用户交互性的应用程序。

解决方案

我假设您的反序列化操作是由业务组件调用的技术组件;所以我会保持尽可能干净和简单:

  public static T Deserialize< T>(string xml)
{
try
{
var serializer = new XmlSerializer(typeof(T));
使用(var sr = new StreamReader(xml))
使用(var reader = XmlReader.Create(sr))
return(T)serializer.Deserialize(reader);
}
catch(异常)
{
//如果需要,清理
throw; //抛出并保持堆栈跟踪
}

在您的调用者或一般的错误处理组件你抓住了exeption;并采取行动例如,记录(包括堆栈跟踪),将异常转换为业务异常等。



请注意:




  • 在您的反序列化操作中,您重新启动异常,保持堆栈跟踪

  • 在你的 Deserialize 操作中你会抛出异常,不返回一个状态。如果这是一个例外,扔它,不要吞下它并依赖于状态。

  • 在你的调用者中,处理异常并做任何你需要做的事:将异常转换为例如WCF服务的故障。只有在处理异常时有不同的行为,才会有不同的捕获。


Let's say I want to deserialize some XML file to a strongly typed object. In case this XML file can't be deserialized (for whatever reason) I would just create a default object and continue normal application workflow without showing any errors to the user. (actually this application is running as Windows service so there is no user for it... for example, imagine application trying to load config file and if fails then just use default config).

My questions is how to create Deserialize() method such that it is easy to use by calling code? My main concerns are how to handle exceptions... Here is my research.

Solution 1:

Here is the simplest way:

    public static T Deserialize<T>(string xml)
    {
        var serializer = new XmlSerializer(typeof (T));
        using (var sr = new StreamReader(xml))
        using (var reader = XmlReader.Create(sr))
            return (T) serializer.Deserialize(reader);
    }

I think usage of this method would be very hard in the calling code because I'd have to handle all possible exceptions that can be thrown by any of these methods/constructors. Calling code doesn't care about that, it only cares whether operation succeeded or not.

So here is my second try:

Solution 2:

    public static T Deserialize<T>(string xml)
    {
        try
        {
            var serializer = new XmlSerializer(typeof (T));
            using (var sr = new StreamReader(xml))
            using (var reader = XmlReader.Create(sr))
                return (T) serializer.Deserialize(reader);
        }
        catch (ArgumentException ex)
        {
            throw new XmlDeserializeException(ValidationExceptionMsg, ex);
        }
        catch (IOException ex)
        {
            throw new XmlDeserializeException(ValidationExceptionMsg, ex);
        }
        catch (XmlSchemaException ex)
        {
            throw new XmlDeserializeException(ValidationExceptionMsg, ex);
        }
        catch (InvalidOperationException ex)
        {
            throw new XmlDeserializeException(ValidationExceptionMsg, ex);
        }
    }

Here I have created a custom exception called XmlDeserializeException and use it to wrap all exceptions that can be thrown by methods (as specified in MSDN) in the try block. Now, the calling code should only catch XmlDeserializeException to know there was an error. However I am not sure how good is this solution... If I need to create a lot of methods like this then all of them would be having a lot of catch blocks that only wrap exception to a custom exception.

So I was wondering would following code is better:

Solution 3:

    public static T Deserialize<T>(string xml)
    {
        try
        {
            var serializer = new XmlSerializer(typeof (T));
            using (var sr = new StreamReader(xml))
            using (var reader = XmlReader.Create(sr))
                return (T) serializer.Deserialize(reader);
        }
        catch (Exception ex)
        {
            throw new XmlDeserializeException(ValidationExceptionMsg, ex);
        }
    }

Here I catch general Exception and wrap it in custom XmlDeserializeException. This way I have reduced code writing, there is no code redundancy and there is less clutter. The calling code will again only have to catch XmlDeserializeException like in solution 2.

Which solution should I use and why? Is there any better way? Please keep in mind the scenario where I want to use this Deserialize() method, this is not a library/framework but rather an application that doesn't have user interactivity.

解决方案

I assume your Deserialize operation is in a technical component that is called by a business component; and so I would keep it as clean and simple as possible:

public static T Deserialize<T>(string xml)
{
    try
    {
        var serializer = new XmlSerializer(typeof (T));
        using (var sr = new StreamReader(xml))
        using (var reader = XmlReader.Create(sr))
            return (T) serializer.Deserialize(reader);
    }
    catch (Exception)
    {
        // clean up if needed 
        throw; // throw and keep stack trace
    }

In your caller or a general error handling component, you catch the exeption; and act on it; for example, do logging (including stack trace), translate exception to business exception etc.

Note that:

  • In your Deserialize operation you rethrow the exception, keeping stack trace
  • In your Deserialize operation you throw an exception, don't return a status. If it is an exception, throw it, don't swallow it and rely on statuses.
  • In your caller, handle the exception and do whatever you have to do: transform the exception to a fault in case of a WCF service, for example. There would be a different catch only if you have different behavior in handling the exception.

这篇关于我应该捕获所有可能的特定异常或只是一般的异常并将其包装在自定义异常中吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆