小编典典

.NET 中 API 重大更改的权威指南

all

我想尽可能多地收集有关 .NET/CLR 中的 API 版本控制的信息,特别是 API 更改如何破坏或不破坏客户端应用程序。首先,让我们定义一些术语:

API 更改 -
公开可见的类型定义的更改,包括其任何公共成员。这包括更改类型和成员名称、更改类型的基类型、从类型的已实现接口列表中添加/删除接口、添加/删除成员(包括重载)、更改成员可见性、重命名方法和类型参数、添加默认值对于方法参数,添加/删除类型和成员的属性,以及添加/删除类型和成员的泛型类型参数(我错过了什么吗?)。这不包括成员机构的任何变化,或私人成员的任何变化(即我们不考虑反射)。

二进制级中断 - API 更改导致针对旧版本 API
编译的客户端程序集可能不会与新版本一起加载。示例:更改方法签名,即使它允许以与以前相同的方式调用(即:void 返回类型/参数默认值重载)。

源代码级中断 - 一种 A​​PI 更改,导致编写的现有代码针对旧版本的 API
进行编译可能无法与新版本一起编译。然而,已经编译的客户端程序集像以前一样工作。示例:添加一个新的重载可能会导致之前明确的方法调用出现歧义。

源代码级别的安静语义更改 - 一种 A​​PI 更改,导致编写的现有代码针对旧版本的 API
进行编译悄悄地更改其语义,例如通过调用不同的方法。然而,代码应该继续编译而没有警告/错误,并且以前编译的程序集应该像以前一样工作。示例:在现有类上实现一个新接口,导致在重载决议期间选择不同的重载。

最终目标是对尽可能多的中断和安静的语义 API
更改进行分类,并描述中断的确切影响,以及哪些语言受其影响和不受其影响。扩展后者:虽然某些更改普遍影响所有语言(例如,向接口添加新成员将破坏该接口在任何语言中的实现),但有些更改需要非常特定的语言语义才能发挥作用才能获得突破。这通常涉及方法重载,并且通常涉及与隐式类型转换有关的任何事情。即使对于符合
CLS 的语言(即至少符合 CLI 规范中定义的“CLS 消费者”规则的语言),似乎也没有任何方法可以在这里定义“最小公分母”——尽管我
如果有人在这里纠正我的错误,我将不胜感激 - 所以这将不得不按语言进行。最感兴趣的自然是 .NET 开箱即用的那些:C#、VB 和 F#;但其他的,如
IronPython、IronRuby、Delphi Prism
等也是相关的。越是极端情况,它就越有趣——移除成员之类的事情是不言而喻的,但是方法重载、可选/默认参数、lambda
类型推断和转换运算符之间的微妙交互可能会非常令人惊讶有时。

几个例子来启动这个:

添加新的方法重载

种类:源级中断

受影响的语言:C#、VB、F#

变更前的 API:

public class Foo
{
    public void Bar(IEnumerable x);
}

变更后的API:

public class Foo
{
    public void Bar(IEnumerable x);
    public void Bar(ICloneable x);
}

示例客户端代码在更改之前工作并在更改之后中断:

new Foo().Bar(new int[0]);

添加新的隐式转换运算符重载

种类:源级中断。

受影响的语言:C#、VB

不受影响的语言:F#

变更前的 API:

public class Foo
{
    public static implicit operator int ();
}

变更后的API:

public class Foo
{
    public static implicit operator int ();
    public static implicit operator float ();
}

示例客户端代码在更改之前工作并在更改之后中断:

void Bar(int x);
void Bar(float x);
Bar(new Foo());

注意:F# 没有被破坏,因为它没有对重载运算符的任何语言级别的支持,无论是显式的还是隐式的 -
两者都必须直接作为op_Explicitop_Implicit方法调用。

添加新的实例方法

Kind:源级安静的语义变化。

受影响的语言:C#、VB

不受影响的语言:F#

变更前的 API:

public class Foo
{
}

变更后的API:

public class Foo
{
    public void Bar();
}

遭受安静语义更改的示例客户端代码:

public static class FooExtensions
{
    public void Bar(this Foo foo);
}

new Foo().Bar();

注意:F# 没有损坏,因为它没有语言级别的支持ExtensionMethodAttribute,并且需要将 CLS 扩展方法作为静态方法调用。


阅读 85

收藏
2022-05-30

共1个答案

小编典典

更改方法签名

种类:二进制中断

受影响的语言:C#(最有可能是 VB 和 F#,但未经测试)

变更前的 API

public static class Foo
{
    public static void bar(int i);
}

变更后的API

public static class Foo
{
    public static bool bar(int i);
}

更改前工作的示例客户端代码

Foo.bar(13);
2022-05-30