System.Runtime.Versioning.ComponentGuaranteesAttribute 类

本文提供了此 API 参考文档的补充说明。

ComponentGuaranteesAttribute组件和类库的开发人员使用该组件和类库来指示其库使用者可以在多个版本中期望的兼容性级别。 它指示将来版本的库或组件不会中断现有客户端的保证级别。 然后 ComponentGuaranteesAttribute ,客户端可以使用辅助功能来设计自己的接口,以确保版本之间的稳定性。

注意

公共语言运行时(CLR)不会以任何方式使用此属性。 其价值在于正式记录组件作者的意图。 编译时工具还可以使用这些声明来检测编译时错误,否则会破坏声明的保证。

兼容性级别

支持 ComponentGuaranteesAttribute 以下级别的兼容性,这些级别由枚举的成员 ComponentGuaranteesOptions 表示:

  • 没有版本到版本兼容性(ComponentGuaranteesOptions.None)。 客户端可以期望将来的版本会中断现有客户端。 有关详细信息,请参阅 本文后面的“无兼容性 ”部分。

  • 并行版本到版本兼容性(ComponentGuaranteesOptions.SideBySide)。 当在同一应用程序域中加载多个版本的程序集时,该组件已经过测试才能正常工作。 通常,将来的版本可能会中断兼容性。 但是,在进行中断性变更时,旧版本不会修改,而是与新版本一起存在。 并行执行是使现有客户端在进行重大更改时正常工作的预期方式。 有关详细信息,请参阅 本文后面的并行兼容性 部分。

  • 稳定的版本到版本兼容性(ComponentGuaranteesOptions.Stable)。 将来的版本不应中断客户端,不需要并行执行。 但是,如果客户端无意中损坏,则可能可以使用并行执行来解决问题。 有关详细信息,请参阅 “稳定兼容性 ”部分。

  • Exchange 版本到版本兼容性(ComponentGuaranteesOptions.Exchange)。 请务必特别注意确保将来的版本不会中断客户端。 客户端应仅在接口签名中使用这些类型,这些类型用于与其他独立于彼此部署的程序集通信。 这些类型的一个版本应位于给定的应用程序域中,这意味着如果客户端中断,并行执行无法解决兼容性问题。 有关详细信息,请参阅 Exchange 类型兼容性 部分。

以下各节更详细地讨论了每种保证级别。

无兼容性

将组件 ComponentGuaranteesOptions.None 标记为指示提供程序无法保证兼容性。 客户端应避免对公开接口产生任何依赖项。 此级别的兼容性对于试验性类型或公开的类型非常有用,但仅适用于始终同时更新的组件。 None 显式指示外部组件不应使用此组件。

并行兼容性

将组件 ComponentGuaranteesOptions.SideBySide 标记为指示在将程序集的多个版本加载到同一应用程序域中时,组件已经过测试才能正常工作。 只要对具有更高版本号的程序集进行更改,就允许中断性变更。 绑定到旧版本的程序集的组件应继续绑定到旧版本,其他组件可以绑定到新版本。 还可以通过破坏性地修改旧版本来更新声明为 SideBySide 的组件。

稳定兼容性

将类型标记为指示该类型 ComponentGuaranteesOptions.Stable 应在各个版本之间保持稳定。 但是,也可以让稳定类型的并行版本存在于同一应用程序域中。

稳定类型维护高二进制兼容性条。 因此,提供程序应避免对稳定类型进行重大更改。 可以接受以下类型的更改:

  • 将专用实例字段添加到或从类型中删除字段,前提是这不会中断序列化格式。
  • 将不可序列化的类型更改为可序列化类型。 (但是,无法将可序列化类型更改为不可序列化的类型。
  • 从方法引发新的派生异常。
  • 提高方法的性能。
  • 更改返回值的范围,只要更改不会对大多数客户端产生不利影响。
  • 修复严重的 bug(如果业务理由较高且受影响的客户端数量较低)。

由于新版稳定组件不应中断现有客户端,因此应用程序域中通常只需要一个稳定组件的版本。 但是,这不是一项要求,因为稳定类型不用作所有组件都同意的已知交换类型。 因此,如果稳定组件的新版本无意中中断了某些组件,并且如果其他组件需要新版本,则可以通过加载旧组件和新组件来解决此问题。

Stable 提供比 . 更强大的版本兼容性保证 None。 这是多版本组件的常见默认值。

Stable 可以与 组合在一起 SideBySide,该组件指出组件不会中断兼容性,但在给定的应用程序域中加载多个版本时进行测试以正常工作。

将类型或方法标记为 Stable后,可以将其升级到 Exchange。 但是,不能将其降级为 None

Exchange 类型兼容性

将类型 ComponentGuaranteesOptions.Exchange 标记为提供更强的版本兼容性保证, Stable应应用于所有类型中最稳定的类型。 这些类型用于在时间(CLR 的任何版本或任何版本的组件或应用程序)和空间(跨进程、跨 CLR 的一个进程中跨应用程序域、一个 CLR 中的跨应用程序域)之间跨所有组件边界之间的交换。 如果对交换类型进行了重大更改,则无法通过加载该类型的多个版本来解决此问题。

仅当问题非常严重(如严重安全问题)或中断概率非常低(即,如果行为已以无法想象的方式被破坏时,才应更改交换类型。 可以对交换类型进行以下类型的更改:

  • 添加新接口定义的继承。

  • 添加新的私有方法,用于实现新继承的接口定义的方法。

  • 添加新的静态字段。

  • 添加新的静态方法。

  • 添加新的非虚拟实例方法。

以下是重大更改,基元类型不允许执行以下操作:

  • 更改序列化格式。 需要版本容错序列化。

  • 添加或删除专用实例字段。 这可能导致更改类型序列化格式以及使用反射的中断客户端代码。

  • 更改类型的可序列化性。 不可序列化的类型可能不可序列化,反之亦然。

  • 从方法引发不同的异常。

  • 更改方法的返回值的范围,除非成员定义引发这种可能性,并清楚地指示客户端应如何处理未知值。

  • 修复大多数 bug。 该类型的使用者将依赖于现有行为。

将组件、类型或成员标记为 Exchange 保证后,不能将其更改为或 StableNone

通常,交换类型是公共接口中常用的基本类型(例如Int32和 .NET 中)和接口(例如IList<T>IEnumerable<T>,和IComparable<T>)。String

Exchange 类型可能只公开标记为 Exchange 兼容性的其他类型。 此外,交换类型不能依赖于容易更改的 Windows API 的行为。

组件保证

下表指示组件的特征和使用如何影响其兼容性保证。

组件特征 Exchange Stable 并排
可以在独立版本的组件之间的接口中使用。 Y N N N
可以由独立版本的程序集使用(私下)。 Y Y Y N
单个应用程序域中可以有多个版本。 N Y Y Y
可以做出重大更改 N N Y Y
经过测试,可以一起加载某些版本的程序集。 N N Y N
可以就地进行重大更改。 N N N Y
可以就地进行非常安全的非中断性服务更改。 Y Y Y Y

应用属性

可以应用于 ComponentGuaranteesAttribute 程序集、类型或类型成员。 其应用程序是分层的。 默认情况下,程序集级别属性定义的 Guarantees 保证定义程序集中的所有类型以及这些类型中的所有成员的保证。 同样,如果保证应用于类型,则默认情况下,它也适用于该类型的每个成员。

可以通过将继承的保证应用于 ComponentGuaranteesAttribute 各个类型和类型成员来重写。 但是,保证替代默认值只能削弱保证;他们不能加强它。 例如,如果程序集标记为 None 有保证,则其类型和成员没有兼容性保证,并且忽略应用于程序集中的类型或成员的任何其他保证。

测试保证

Guarantees 属性返回枚举的成员 ComponentGuaranteesOptions ,该成员用 FlagsAttribute 属性标记。 这意味着应通过屏蔽可能未知的标志来测试你感兴趣的标志。 例如,以下示例测试类型是否标记为 Stable

// Test whether guarantee is Stable.
if ((guarantee & ComponentGuaranteesOptions.Stable) == ComponentGuaranteesOptions.Stable)
   Console.WriteLine("{0} is marked as {1}.", typ.Name, guarantee);
' Test whether guarantee is Stable.
If (guarantee And ComponentGuaranteesOptions.Stable) = ComponentGuaranteesOptions.Stable Then
   Console.WriteLine("{0} is marked as {1}.", typ.Name, guarantee)
End If

以下示例测试类型是否标记为 StableExchange

// Test whether guarantee is Stable or Exchange.
if ((guarantee & (ComponentGuaranteesOptions.Stable | ComponentGuaranteesOptions.Exchange)) > 0)
   Console.WriteLine("{0} is marked as Stable or Exchange.", typ.Name, guarantee);
' Test whether guarantee is Stable or Exchange.
If (guarantee And (ComponentGuaranteesOptions.Stable Or ComponentGuaranteesOptions.Exchange)) > 0 Then
   Console.WriteLine("{0} is marked as Stable or Exchange.", typ.Name, guarantee)
End If

以下示例测试类型被标记为None(即,既不是)也不StableExchange标记的。

// Test whether there is no guarantee (neither Stable nor Exchange).
if ((guarantee & (ComponentGuaranteesOptions.Stable | ComponentGuaranteesOptions.Exchange)) == 0)
   Console.WriteLine("{0} has no compatibility guarantee.", typ.Name, guarantee);
' Test whether there is no guarantee (neither Stable nor Exchange).
If (guarantee And (ComponentGuaranteesOptions.Stable Or ComponentGuaranteesOptions.Exchange)) = 0 Then
   Console.WriteLine("{0} has no compatibility guarantee.", typ.Name, guarantee)
End If