会影响兼容性的变更Changes that affect compatibility

在 .NET 的整个历史记录中,它都尝试在版本之间以及 .NET 各个风格之间保持高级别的兼容性。Throughout its history, .NET has attempted to maintain a high level of compatibility from version to version and across flavors of .NET. .NET Core 将继续坚守这个准则。This continues to be true for .NET Core. 尽管可以将 .NET Core 视为独立于 .NET Framework 的新技术,但下面的两个因素使 .NET Core 无法脱离 .NET Framework:Although .NET Core can be considered as a new technology that is independent of the .NET Framework, two major factors limit the ability of .NET Core to diverge from .NET Framework:

  • 有许多最初开发过或在继续开发 .NET Framework 应用程序的开发人员。A large number of developers either originally developed or continue to develop .NET Framework applications. 他们希望各个 .NET 实现中的行为保持一致。They expect consistent behavior across .NET implementations.

  • .NET Standard 库项目允许开发人员创建面向 .NET Core 和 .NET Framework 共享的通用 API 的库。.NET Standard library projects allow developers to create libraries that target common APIs shared by .NET Core and .NET Framework. 开发人员希望用于 .NET Core 应用程序的库与用于 .NET Framework 应用程序的同一个库的行为相同。Developers expect that a library used in a .NET Core application should behave identically to the same library used in a .NET Framework application.

在希望保持各个 .NET 实现之间的兼容性的同时,开发人员还希望在各个 .NET Core 版本之间保持高级别的兼容性。Along with compatibility across .NET implementations, developers expect a high level of compatibility across .NET Core versions. 具体而言,为 .NET Core 早期版本编写的代码应在较高版本的 .NET Core 上无缝运行。In particular, code written for an earlier version of .NET Core should run seamlessly on a later version of .NET Core. 实际上,许多开发人员都希望新发布的 .NET Core 版本中的新 API 也应该与引入这些 API 的预发布版本兼容。In fact, many developers expect that the new APIs found in newly released versions of .NET Core should also be compatible with the pre-release versions in which those APIs were introduced.

本文概述了兼容性变更(或中断性变更)的类别,以及 .NET 团队如何评估各个类别中的变更。This article outlines the categories of compatibility changes (or breaking changes) and the way in which the .NET team evaluates changes in each of these categories. 如果开发人员需打开 dotnet/runtime GitHub 存储库中要求修改现有 API 的行为的拉取请求,则了解 .NET 团队如何处理可能的中断性变更对他们来说尤其有用。Understanding how the .NET team approaches possible breaking changes is particularly helpful for developers who open pull requests in the dotnet/runtime GitHub repository that modify the behavior of existing APIs.

备注

若要查看兼容性类别的定义,如二进制兼容性和向后兼容性,请参阅中断性变更类别For a definition of compatibility categories, such as binary compatibility and backward compatibility, see Breaking change categories.

以下各个部分说明了 .NET Core API 的变更类别,以及它们对应用程序兼容性的影响。The following sections describe the categories of changes made to .NET Core APIs and their impact on application compatibility. ✔️ 表示允许更改;❌ 表示不允许更改;❓ 表示需要评判之前行为的可预测性、显著性和一致性。Changes are either allowed ✔️, disallowed ❌, or require judgment and an evaluation of how predictable, obvious, and consistent the previous behavior was ❓.

备注

除了将这些准则用作 .NET Core 库变更评估指南以外,库开发人员还可以使用它们评估他们自己的面向多个 .NET 实现和版本的库更改。In addition to serving as a guide to how changes to .NET Core libraries are evaluated, library developers can also use these criteria to evaluate changes to their libraries that target multiple .NET implementations and versions.

公共协定修改Modifications to the public contract

此类别的变更会修改类型的公共外围应用。Changes in this category modify the public surface area of a type. 禁止此类别中的多数变更,因为它们违反了向后兼容性(使用早期 API 版本生成的应用程序的功能:无需在较高版本上重新编译即可运行)。 Most of the changes in this category are disallowed since they violate backwards compatibility (the ability of an application that was developed with a previous version of an API to execute without recompilation on a later version).

类型Types

  • ✔️ 允许: 基类型已实现接口时,从类型中删除接口实现✔️ ALLOWED: Removing an interface implementation from a type when the interface is already implemented by a base type

  • ❓ 需要评判: 向类型添加新的接口实现REQUIRES JUDGMENT: Adding a new interface implementation to a type

    此为可接受的变更,因为它不会对现有客户端产生不良影响。This is an acceptable change because it does not adversely affect existing clients. 对此类型的任何变更必须在此处定义的可接受变更的边界内工作,新实现才能继续成为可接受的实现。Any changes to the type must work within the boundaries of acceptable changes defined here for the new implementation to remain acceptable. 添加直接影响设计器或序列化程序功能(生成无法供低级使用的代码或数据的功能)的接口时,需要格外注意。Extreme caution is necessary when adding interfaces that directly affect the ability of a designer or serializer to generate code or data that cannot be consumed down-level. 例如 ISerializable 接口。An example is the ISerializable interface.

  • ❓ 需要评判: 引入新的基类REQUIRES JUDGMENT: Introducing a new base class

    若类型未引入任何新的抽象成员且未更改现有类型的语义或行为,可以将它引入到两个现有类型之间的层次结构。A type can be introduced into a hierarchy between two existing types if it doesn't introduce any new abstract members or change the semantics or behavior of existing types. 例如,在 .NET Framework 2.0 中,DbConnection 类成为之前直接派生自 ComponentSqlConnection 的新基类。For example, in .NET Framework 2.0, the DbConnection class became a new base class for SqlConnection, which had previously derived directly from Component.

  • ✔️ 允许: 将某个程序集中的类型移动到另一个程序集中✔️ ALLOWED: Moving a type from one assembly to another

    旧程序集必须标有指向新程序集的 TypeForwardedToAttributeThe old assembly must be marked with the TypeForwardedToAttribute that points to the new assembly.

  • ✔️ 允许: 将 struct 类型更改为 readonly struct 类型✔️ ALLOWED: Changing a struct type to a readonly struct type

    不允许将 readonly struct 类型更改为 struct 类型。Changing a readonly struct type to a struct type is not allowed.

  • ✔️ 允许: 没有可访问的(public 或 protected)构造函数时,向类型添加 sealedabstract 关键字✔️ ALLOWED: Adding the sealed or abstract keyword to a type when there are no accessible (public or protected) constructors

  • ✔️ 允许: 扩展类型的可见性✔️ ALLOWED: Expanding the visibility of a type

  • ❌ 不允许: 更改类型的命名空间或名称DISALLOWED: Changing the namespace or name of a type

  • ❌ 不允许: 重命名或删除公共类型DISALLOWED: Renaming or removing a public type

    这将中断使用重命名的或删除的类型的所有代码。This breaks all code that uses the renamed or removed type.

  • ❌ 不允许: 更改枚举的基础类型DISALLOWED: Changing the underlying type of an enumeration

    此为编译时和行为中断性变更,此外它还是可能会导致属性参数不可分析的二进制中断性更改。This is a compile-time and behavioral breaking change as well as a binary breaking change that can make attribute arguments unparsable.

  • ❌ 不允许: 密封之前未密封的类型DISALLOWED: Sealing a type that was previously unsealed

  • ❌ 不允许: 向接口的一组基类型添加接口DISALLOWED: Adding an interface to the set of base types of an interface

    若接口实现它未曾实现过的接口,将中断实现此接口的原始版本的所有类型。If an interface implements an interface that it previously did not implement, all types that implemented the original version of the interface are broken.

  • ❓ 需要评判: 从一组基类删除某个类,或从一组实现的接口删除某个接口REQUIRES JUDGMENT: Removing a class from the set of base classes or an interface from the set of implemented interfaces

    接口删除规则有一个例外情况:可以添加派生自删除的接口的接口实现。There is one exception to the rule for interface removal: you can add the implementation of an interface that derives from the removed interface. 例如,如果类型或接口现在实现将实现 IDisposableIComponent,则可以删除 IDisposableFor example, you can remove IDisposable if the type or interface now implements IComponent, which implements IDisposable.

  • ❌ 不允许: 将 readonly struct 类型更改为 struct 类型DISALLOWED: Changing a readonly struct type to a struct type

    但允许将 struct 类型更改为 readonly struct 类型。The change of a struct type to a readonly struct type is allowed, however.

  • ❌ 不允许: 将 struct 类型更改为 ref struct 类型,或将后者改为前者DISALLOWED: Changing a struct type to a ref struct type, and vice versa

  • ❌ 不允许: 缩小类型的可见性DISALLOWED: Reducing the visibility of a type

    但允许增大类型的可见性。However, increasing the visibility of a type is allowed.

成员Members

  • ✔️ 允许: 扩展非 virtual 成员的可见性✔️ ALLOWED: Expanding the visibility of a member that is not virtual

  • ✔️ 允许: 向不包含任何可访问的(public 或 protected)构造函数或为 sealed 类型的公共类型添加抽象成员✔️ ALLOWED: Adding an abstract member to a public type that has no accessible (public or protected) constructors, or the type is sealed

    但不允许向包含可访问的(公共或受保护的)构造函数且非 sealed 类型的类型添加抽象成员。However, adding an abstract member to a type that has accessible (public or protected) constructors and is not sealed is not allowed.

  • ✔️ 允许: 类型不包含任何可访问的(public 或 protected)构造函数或类型为 sealed 类型时,限制 protected 成员的可见性✔️ ALLOWED: Restricting the visibility of a protected member when the type has no accessible (public or protected) constructors, or the type is sealed

  • ✔️ 允许: 将成员移动到层次结构中高于删除的成员所在的类型的类✔️ ALLOWED: Moving a member into a class higher in the hierarchy than the type from which it was removed

  • ✔️ 允许: 添加或删除重写✔️ ALLOWED: Adding or removing an override

    引入重写可能会导致先前的使用者在调用 base 时跳过重写。Introducing an override might cause previous consumers to skip over the override when calling base.

  • ✔️ 允许: 向类添加构造函数及无参数构造函数(若该类过去没有任何构造函数)✔️ ALLOWED: Adding a constructor to a class, along with a parameterless constructor if the class previously had no constructors

    但是,不允许在未对过去不包含任何构造函数的类添加无参数构造函数的情况下向其添加构造函数。 However, adding a constructor to a class that previously had no constructors without adding the parameterless constructor is not allowed.

  • ✔️ 允许: 将成员从 abstract 更改为 virtual✔️ ALLOWED: Changing a member from abstract to virtual

  • ✔️ 允许: 从 ref readonly 更改为 ref 返回值(虚拟方法或接口除外)✔️ ALLOWED: Changing from a ref readonly to a ref return value (except for virtual methods or interfaces)

  • ✔️ 允许: 若字段的静态类型为非可变的值类型,从字段删除 readonly✔️ ALLOWED: Removing readonly from a field, unless the static type of the field is a mutable value type

  • ✔️ 允许: 调用未曾定义的新事件✔️ ALLOWED: Calling a new event that wasn't previously defined

  • ❓ 需要评判: 向类型添加新实例字段REQUIRES JUDGMENT: Adding a new instance field to a type

    此变更影响序列化。This change impacts serialization.

  • ❌ 不允许: 重命名或删除公共成员或参数DISALLOWED: Renaming or removing a public member or parameter

    这将中断使用重命名的或删除的成员或参数的所有代码。This breaks all code that uses the renamed or removed member, or parameter.

    这包括删除或重命名属性中的 Getter 或资源库,以及重命名或删除枚举成员。This includes removing or renaming a getter or setter from a property, as well as renaming or removing enumeration members.

  • ❌ 不允许: 向接口添加成员DISALLOWED: Adding a member to an interface

  • ❌ 不允许: 更改公共常量或枚举成员的值DISALLOWED: Changing the value of a public constant or enumeration member

  • ❌ 不允许: 更改属性类型、字段、参数或返回值DISALLOWED: Changing the type of a property, field, parameter, or return value

  • ❌ 不允许: 添加、删除、或更改参数的顺序DISALLOWED: Adding, removing, or changing the order of parameters

  • ❌ 不允许: 向参数添加或从中删除 inoutref 关键字DISALLOWED: Adding or removing the in, out , or ref keyword from a parameter

  • ❌ 不允许: 重命名参数(包括更改其大小写)DISALLOWED: Renaming a parameter (including changing its case)

    鉴于以下两个原因将此视为中断性变更:This is considered breaking for two reasons:

  • ❌ 不允许: 从 ref 返回值更改为 ref readonly 返回值DISALLOWED: Changing from a ref return value to a ref readonly return value

  • ❌️ 不允许: 在虚拟方法或接口上从 ref readonly 更改为 ref 返回值❌️ DISALLOWED: Changing from a ref readonly to a ref return value on a virtual method or interface

  • ❌ 不允许: 向成员添加或从中删除 abstractDISALLOWED: Adding or removing abstract from a member

  • ❌ 不允许: 从成员删除 virtual 关键字DISALLOWED: Removing the virtual keyword from a member

    通常这不属于中断性变更,因为 C# 编译器通常会发出 callvirt 中间语言 (IL) 指令来调用非虚拟方法(callvirt 执行 null 检查,而常规调用不会执行此检查),鉴于下列原因此行为非恒定:While this often is not a breaking change because the C# compiler tends to emit callvirt Intermediate Language (IL) instructions to call non-virtual methods (callvirt performs a null check, while a normal call doesn't), this behavior is not invariable for several reasons:

    • C# 并非 .NET 面向的唯一语言。C# is not the only language that .NET targets.

    • 目标方法为非虚拟且可能非 null 时(如通过 ?. null 传播运算符访问的方法),C# 编译器逐渐尝将 callvirt 优化为常规调用。The C# compiler increasingly tries to optimize callvirt to a normal call whenever the target method is non-virtual and is probably not null (such as a method accessed through the ?. null propagation operator).

    使方法成为虚拟方法意味着使用者代码通常最终要以非虚拟方式调用它。Making a method virtual means that the consumer code would often end up calling it non-virtually.

  • ❌ 不允许: 向成员添加 virtual 关键字DISALLOWED: Adding the virtual keyword to a member

  • ❌ 不允许: 使 virtual 成员成为 abstract 成员DISALLOWED: Making a virtual member abstract

    抽象成员提供可以由派生类重写的方法实现。 A virtual member provides a method implementation that can be overridden by a derived class. 抽象成员不提供任何实现,且必须重写。 An abstract member provides no implementation and must be overridden.

  • ❌ 不允许: 向包含可访问的(public 或 protected)构造函数且非 sealed 类型的公共类型添加抽象成员DISALLOWED: Adding an abstract member to a public type that has accessible (public or protected) constructors and that is not sealed

  • ❌ 不允许: 向成员添加或从中删除 static 关键字DISALLOWED: Adding or removing the static keyword from a member

  • ❌ 不允许: 添加排除现有重载并定义其他行为的重载DISALLOWED: Adding an overload that precludes an existing overload and defines a different behavior

    这将中断已绑定先前重载的现有客户端。This breaks existing clients that were bound to the previous overload. 例如,若类包含单个接受 UInt32 的方法的版本,传递 Int32 值时,现有使用者将成功地绑定该重载。For example, if a class has a single version of a method that accepts a UInt32, an existing consumer will successfully bind to that overload when passing a Int32 value. 但是,如果添加接受 Int32 的重载,重新编译或使用晚期绑定时,编译器现在将绑定新的重载。However, if you add an overload that accepts an Int32, when recompiling or using late-binding, the compiler now binds to the new overload. 若生成不同的行为,则它属于中断性变更。If different behavior results, this is a breaking change.

  • ❌ 不允许: 只向过去不包含任何构造函数的类添加构造函数而不添加无参数构造函数DISALLOWED: Adding a constructor to a class that previously had no constructor without adding the parameterless constructor

  • ❌️ 不允许: 向字段添加 readonly❌️ DISALLOWED: Adding readonly to a field

  • ❌ 不允许: 降低成员的可见性DISALLOWED: Reducing the visibility of a member

    这包括在存在可访问的( publicprotected )构造函数且类型非 sealed 的情况下降低 protected 成员的可见性。This includes reducing the visibility of a protected member when there are accessible (public or protected) constructors and the type is not sealed. 若不属于上述情况,则允许降低受保护的成员的可见性。If this is not the case, reducing the visibility of a protected member is allowed.

    允许增大成员的可见性。Increasing the visibility of a member is allowed.

  • ❌ 不允许: 更改成员的类型DISALLOWED: Changing the type of a member

    不可修改方法的返回值、属性类型或字段。The return value of a method or the type of a property or field cannot be modified. 例如,不可将返回 Object 的方法的签名更改为返回 String,反之亦然。For example, the signature of a method that returns an Object cannot be changed to return a String, or vice versa.

  • ❌ 不允许: 向先前没有任何状态的结构添加字段DISALLOWED: Adding a field to a struct that previously had no state

    有明确的分配规则规定,只要变量类型为无状态结构,即允许使用未初始化的变量。Definite assignment rules allow the use of uninitialized variables so long as the variable type is a stateless struct. 若结构成为有状态结构,代码可能最终成为未初始化的数据。If the struct is made stateful, code could end up with uninitialized data. 这可能既是源中断性变更,又是二进制中断性变更。This is both potentially a source breaking and a binary breaking change.

  • ❌ 不允许: 触发先前从未触发过的现有事件DISALLOWED: Firing an existing event when it was never fired before

行为变更Behavioral changes

程序集Assemblies

  • ✔️ 允许: 使程序集成为可移植的程序集并且仍支持同样的平台✔️ ALLOWED: Making an assembly portable when the same platforms are still supported

  • ❌ 不允许: 更改程序集的名称DISALLOWED: Changing the name of an assembly

  • ❌ 不允许: 更改程序集的公钥DISALLOWED: Changing the public key of an assembly

属性、字段、参数和返回值Properties, fields, parameters, and return values

  • ✔️ 允许: 将属性、字段、返回值或 out 参数的值更改为派生程度更大的类型✔️ ALLOWED: Changing the value of a property, field, return value, or out parameter to a more derived type

    例如,返回 Object 的类型的方法可能返回 String 实例。For example, a method that returns a type of Object can return a String instance. (但是不可更改方法签名。)(However, the method signature cannot change.)

  • ✔️ 允许: 在成员为非 virtual 成员时,扩大属性或参数的可接受值的范围✔️ ALLOWED: Increasing the range of accepted values for a property or parameter if the member is not virtual

    可以扩展可传递到方法或由成员返回的值范围,但不可扩展参数或成员类型。While the range of values that can be passed to the method or are returned by the member can expand, the parameter or member type cannot. 例如,传递到方法的值可以从 0-124 扩展到 0-255,但参数类型不可从 Byte 更改为 Int32For example, while the values passed to a method can expand from 0-124 to 0-255, the parameter type cannot change from Byte to Int32.

  • ❌ 不允许: 在成员为 virtual 成员时,扩大属性或参数的可接受值的范围DISALLOWED: Increasing the range of accepted values for a property or parameter if the member is virtual

    此变更将中断已重写的现有成员,面向扩展的值范围时它们将无法正常运行。This change breaks existing overridden members, which will not function correctly for the extended range of values.

  • ❌ 不允许: 缩小属性或参数的可接受值的范围DISALLOWED: Decreasing the range of accepted values for a property or parameter

  • ❌ 不允许: 扩大属性的返回值范围、字段、返回值或 out 参数DISALLOWED: Increasing the range of returned values for a property, field, return value, or out parameter

  • ❌ 不允许: 更改属性的返回值、字段、方法返回值或 out 参数DISALLOWED: Changing the returned values for a property, field, method return value, or out parameter

  • ❌ 不允许: 更改属性、字段或参数的默认值DISALLOWED: Changing the default value of a property, field, or parameter

  • ❌ 不允许: 更改数值返回值的精度DISALLOWED: Changing the precision of a numeric return value

  • ❓ 需要评判: 关于输入分析和新异常引发的变更(尽管本文档未指定分析行为)REQUIRES JUDGMENT: A change in the parsing of input and throwing new exceptions (even if parsing behavior is not specified in the documentation

异常Exceptions

  • ✔️ 允许: 引发派生程度高于现有异常的异常✔️ ALLOWED: Throwing a more derived exception than an existing exception

    由于新异常是现有异常的子类,先前的异常处理代码将继续处理异常。Because the new exception is a subclass of an existing exception, previous exception handling code continues to handle the exception. 例如,在 .NET Framework 4 中,找不到区域性时,区域性生成和检索方法开始引发 CultureNotFoundException 而不引发 ArgumentExceptionFor example, in .NET Framework 4, culture creation and retrieval methods began to throw a CultureNotFoundException instead of an ArgumentException if the culture could not be found. 由于 CultureNotFoundException 派生自 ArgumentException,因此这是可接受的变更。Because CultureNotFoundException derives from ArgumentException, this is an acceptable change.

  • ✔️ 允许: 引发比 NotSupportedExceptionNotImplementedExceptionNullReferenceException 更加具体的异常✔️ ALLOWED: Throwing a more specific exception than NotSupportedException, NotImplementedException, NullReferenceException

  • ✔️ 允许: 引发被视为无法恢复的异常✔️ ALLOWED: Throwing an exception that is considered unrecoverable

    不应捕获无法恢复的异常,而应该由高级别的全部捕获处理程序处理它们。Unrecoverable exceptions should not be caught but instead should be handled by a high-level catch-all handler. 因此,用户不应该拥有捕获这些显式异常的代码。Therefore, users are not expected to have code that catches these explicit exceptions. 无法恢复的异常包括:The unrecoverable exceptions are:

  • ✔️ 允许: 在新的代码路径中引发新的异常✔️ ALLOWED: Throwing a new exception in a new code path

    异常必须仅适用于使用新参数值或状态执行并且无法由面向先前版本的现有代码执行的新代码路径。The exception must apply only to a new code-path that's executed with new parameter values or state and that can't be executed by existing code that targets the previous version.

  • ✔️ 允许: 删除异常,以启用更可靠的行为或新方案✔️ ALLOWED: Removing an exception to enable more robust behavior or new scenarios

    例如,可以以其他方式将先前仅处理正值并引发 ArgumentOutOfRangeExceptionDivide 方法更改为同时支持正值和负值并且不引发异常。For example, a Divide method that previously only handled positive values and threw an ArgumentOutOfRangeException otherwise can be changed to support both negative and positive values without throwing an exception.

  • ✔️ 允许: 更改错误消息的文本✔️ ALLOWED: Changing the text of an error message

    开发人员不应依赖也会基于用户区域性更改的错误消息文本。Developers should not rely on the text of error messages, which also change based on the user's culture.

  • ❌ 不允许: 在上文未列出的任何其他的情况下引发异常DISALLOWED: Throwing an exception in any other case not listed above

  • ❌ 不允许: 在上文未列出的任何其他的情况下删除异常DISALLOWED: Removing an exception in any other case not listed above

特性Attributes

  • ✔️ 允许: 更改不可观测的属性的值✔️ ALLOWED: Changing the value of an attribute that is not observable

  • ❌ 不允许: 更改可观测的属性的值DISALLOWED: Changing the value of an attribute that is observable

  • ❓ 需要评判: 删除属性REQUIRES JUDGMENT: Removing an attribute

    多数情况下,删除属性(如 NonSerializedAttribute)为中断性变更。In most cases, removing an attribute (such as NonSerializedAttribute) is a breaking change.

平台支持Platform support

  • ✔️ 允许: 在平台上支持先前不支持的操作✔️ ALLOWED: Supporting an operation on a platform that was previously not supported

  • ❌ 不允许: 对于平台先前支持的操作,不再支持或者现在需要特定服务包DISALLOWED: Not supporting or now requiring a specific service pack for an operation that was previously supported on a platform

内部实现变更Internal implementation changes

  • ❓ 需要评判: 更改内部类型的外围应用REQUIRES JUDGMENT: Changing the surface area of an internal type

    尽管此类更改将中断私有反射,但通常允许这些变更。Such changes are generally allowed, although they break private reflection. 如果常用的第三方库或大量开发人员依赖内部 API,在这些情况下,可能不允许此类变更。In some cases, where popular third-party libraries or a large number of developers depend on the internal APIs, such changes may not be allowed.

  • ❓ 需要评判: 更改成员的内部实现REQUIRES JUDGMENT: Changing the internal implementation of a member

    尽管此类更改将中断私有反射,但通常允许这些变更。These changes are generally allowed, although they break private reflection. 如果客户代码频繁依赖私有反射,或者变更引入意外的负面影响,在这些情况下,可能不允许这些变更。In some cases, where customer code frequently depends on private reflection or where the change introduces unintended side effects, these changes may not be allowed.

  • ✔️ 允许: 提高操作的性能✔️ ALLOWED: Improving the performance of an operation

    修改操作性能的功能必不可少,但此类变更可能会中断依赖操作的当前速度的代码。The ability to modify the performance of an operation is essential, but such changes can break code that relies upon the current speed of an operation. 这一点尤其适用于对于依赖异步操作计时的代码。This is particularly true of code that depends on the timing of asynchronous operations. 性能更改应不影响所说的 API 的其他行为;否则,变更将属于中断性变更。The performance change should have no effect on other behavior of the API in question; otherwise, the change will be breaking.

  • ✔️ 允许: 间接更改操作性能(通常产生的是负面影响)✔️ ALLOWED: Indirectly (and often adversely) changing the performance of an operation

    若出于某些其他的原因未将所说的变更归类为中断性变更,这是可以接受的。If the change in question is not categorized as breaking for some other reason, this is acceptable. 通常需要执行可能包含额外操作或添加新功能的操作。Often, actions need to be taken that may include extra operations or that add new functionality. 这几乎都会影响性能,但对于使所说的 API 按预期方式运行而言它可能必不可少。This will almost always affect performance but may be essential to make the API in question function as expected.

  • ❌ 不允许: 将同步 API 更改为异步(反之亦然)DISALLOWED: Changing a synchronous API to asynchronous (and vice versa)

代码更改Code changes

  • ✔️ 允许: 向参数添加 params✔️ ALLOWED: Adding params to a parameter

  • ❌ 不允许: 将 struct 更改为 class,或将后者改为前者DISALLOWED: Changing a struct to a class and vice versa

  • ❌ 不允许: 向代码块添加 checked 关键字DISALLOWED: Adding the checked keyword to a code block

    此变更可能导致先前执行的代码引发 OverflowException,此为不可接受的变更。This change may cause code that previously executed to throw an OverflowException and is unacceptable.

  • ❌ 不允许: 从参数删除 paramsDISALLOWED: Removing params from a parameter

  • ❌ 不允许: 更改事件的触发顺序DISALLOWED: Changing the order in which events are fired

    开发人员可以合理地期望事件按相同的顺序触发,开发人员代码频繁依赖事件的触发顺序。Developers can reasonably expect events to fire in the same order, and developer code frequently depends on the order in which events are fired.

  • ❌ 不允许: 删除给定操作上的事件引发DISALLOWED: Removing the raising of an event on a given action

  • ❌ 不允许: 更改给定事件的调用次数DISALLOWED: Changing the number of times given events are called

  • ❌ 不允许: 向枚举类型添加 FlagsAttributeDISALLOWED: Adding the FlagsAttribute to an enumeration type