【问题标题】:Are all .NET exceptions serializable?所有 .NET 异常都可序列化吗?
【发布时间】:2010-09-25 10:41:41
【问题描述】:

所有 .NET 异常对象都可以序列化吗?

【问题讨论】:

    标签: c# .net exception


    【解决方案1】:

    是和不是。正如 Jeff 和其他人所指出的,所有异常类都应该并且几乎总是可序列化的。如果您遇到不可序列化的特定异常类,则很可能是一个错误。

    但是在考虑可序列化性时,您需要同时考虑直接类和属于该类型成员的所有类型(这是一个递归过程)。基 Exception 类有一个 Data 属性,它的类型是 IDictionary。这是有问题的,因为它允许您或其他任何人将任何对象添加到异常中。如果此对象不可序列化,则异常的序列化将失败。

    Data 属性的默认实现会进行一些基本检查,以确保添加的对象是可序列化的。但它在几个方面存在缺陷

    • 仅对类型的可序列化性进行顶级检查,并且此检查仅通过检查 Type.IsSerializable(不是 100% 可靠检查)来完成。
    • 属性是虚拟的。派生的异常类型可以覆盖并使用执行 0 检查的 Hashtable。

    【讨论】:

      【解决方案2】:

      这个问题已经得到了充分的回答,但是对于刚接触C#或序列化的程序员来说,我认为指出一般情况下异常NOT可序列化实际上很有帮助!

      这听起来可能有点挑衅,但让我解释一下。

      确实所有的异常都实现了 ISerializable 接口,但这只是表明它应该是可序列化的。但是实现接口不会使对象可序列化(在这种情况下,这意味着异常可以被序列化反序列化)。

      正如其他人所指出的,对这个问题的最准确答案是 .Net 框架 中的许多但肯定不是所有例外都是可序列化的。但是,如果问题是在更广泛的范围内使用术语“.Net Exception”,例如一个异常派生 System.Exception,那么就最佳实践和避免错误而言,更好和更有帮助的答案是我上面所做的断言,一般来说异常是不可序列化的。

      原因如下: 如前所述,对于真正可序列化的异常,它必须具有正确的构造函数ctor(SerializationInfo, StreamingContext),并且必须使用正确的属性进行修饰。重要的是,如果省略这些约束,它们都不会导致编译器错误!

      这意味着从 Exception 派生的 NO 类是可序列化的,除非采取这些额外的、可选的(从编译器的角度来看)步骤。

      即任何衍生出如下新异常的未经验丰富/不了解的编码人员刚刚创建了一个不可序列化的异常。

      class MyNewException : Exception { }
      

      Visual Studio 有一个很棒的“异常”sn-p,它可以让您非常快速地生成新的可序列化异常。但即使在这种情况下,也没有什么可以提醒或帮助程序员实际序列化对象属性。例如,即使下面的类具有适当的构造函数和属性,如果没有构造函数和 GetObjectData 中的附加代码,MyNewField 属性也不会被序列化。

      class MyNewException : Exception 
      {
          public MyNewField { get; set; }
      }
      

      因此,这里的重点是,如果您出于某种原因必须依赖正确的异常序列化和反序列化,则应该完全意识到,当涉及到任何自定义代码或程序集时,并不能保证它会起作用。此外,由于所需的构造函数通常受到保护,因此您不一定能够轻松验证它是否存在(无需反射)。

      在我自己的项目中,我在某些时候创建了异常“代理”,它可以存储来自自身不可序列化的异常的一些信息(例如消息等)。这些可用于序列化某些信息,或者反序列化由没有适当构造函数的异常写入的数据。

      【讨论】:

      • GetObjectData 上的注释这样的优点很少,但也有几个很不正确的说法。例如“衍生一个新的异常,如下所示,刚刚创建了一个不可序列化的异常。”是不正确的。 ISerializable 接口被继承并且类将是可序列化的。也许这在 2012 年是正确的,IDK。它是否可反序列化是另一回事。有几个陈述没有做出这种区分。无论如何,大多数人只会关心序列化,因为许多异常日志框架都需要它。
      【解决方案3】:

      System.Exception 实现 ISerializable 并且它是所有异常的基类,所以是的。

      见:http://msdn.microsoft.com/en-us/library/system.exception.aspx

      【讨论】:

      • 除了派生类不继承SerializableAttribute,因此每个派生类也必须进行修饰,以使该类可序列化。
      【解决方案4】:

      System.Exception 实现了ISerializable,但是如果后代没有实现带有签名(SerializationInfo,StreamingContext) 的正确重载构造函数,则后代可能不会反序列化。

      【讨论】:

      • 另外,如果派生异常没有正确调用base.GetObjectData,那么基异常的信息将不会被序列化,这会导致反序列化时出错。无论哪种情况(缺少构造函数或序列化基数失败),序列化都会成功,但反序列化会抛出异常。
      【解决方案5】:

      是的,但从历史上看(没有双关语)例外。

      换句话说,所有异常都应该是可序列化的,但是来自第三方代码的一些自定义异常可能不是,这取决于它们的实现方式。

      例如,在 .NET 1.0 时代,来自官方 Microsoft Oracle 数据库提供商的异常由于代码中的错误而无法序列化。

      【讨论】:

      • 即使从 .Net 4.5 开始,由于缺少所需的构造函数,一些 OleDB 数据库异常和一些 System.Net 异常也无法反序列化。
      猜你喜欢
      • 2011-05-31
      • 2013-04-30
      • 2014-04-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-20
      相关资源
      最近更新 更多