我应该捕获所有可能的特定异常还是仅仅是一般异常并将其包装在自定义异常中?

时间:2014-04-28 11:40:35

标签: c# .net exception serialization exception-handling

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

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

解决方案1:

这是最简单的方法:

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

我认为在调用代码中使用这个方法会非常困难,因为我必须处理所有可能由这些方法/构造函数抛出的异常。调用代码并不关心它,它只关心操作是否成功。

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

解决方案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);
        }
    }

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

所以我想知道下面的代码会更好:

解决方案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);
        }
    }

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

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

3 个答案:

答案 0 :(得分:1)

如果你以相同的方式处理异常,那么在捕获不同的情况下确实没有意义,在这种情况下,你会将杂乱的情况降到最低,并采用解决方案3.

解决方案2只需要更多代码来完成同样的事情。

答案 1 :(得分:1)

在你的问题中你说:

  

我想说我想将一些XML文件反序列化为强类型   宾语。如果这个XML文件无法反序列化(无论如何)   原因)我只想创建一个默认对象并继续正常   应用程序工作流程,不会向用户显示任何错误。

如果你没有对异常做任何事情(如你所述,没有用户界面,只有窗口服务),你可以记录你的异常,并返回default(T)而不是传播异常,如下所示:

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)
        {
            // Log exception here:
            Logger.Log(...)
            return default(T);
        }
    }

答案 2 :(得分:1)

我假设您的Deserialize操作位于由业务组件调用的技术组件中;所以我会尽量保持简洁:

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
    }

在您的调用者或一般错误处理组件中,您可以捕获该异常;并采取行动;例如,执行日志记录(包括堆栈跟踪),将异常转换为业务异常等。

请注意:

  • Deserialize操作中,您重新抛出异常,保持堆栈跟踪
  • 在您的Deserialize操作中抛出异常,请勿返回状态。如果是例外,抛弃它,不要吞下它并依赖状态。
  • 在您的调用者中,处理异常并执行您必须执行的操作:例如,在WCF服务的情况下将异常转换为错误。只有在处理异常时有不同的行为时才会有不同的捕获。