我想尽可能多地收集有关.NET/CLR中的API版本控制的信息,特别是API更改如何影响或不 destruct 客户端应用程序.首先,我们来定义一些术语:
API change-类型(包括其任何公共成员)的公开可见定义的更改.这包括更改类型和成员名称、更改类型的基类型、在类型的已实现接口列表中添加/移除接口、添加/移除成员(包括重载)、更改成员可见性、重命名方法和类型参数、添加方法参数的默认值、添加/移除类型和成员的属性,以及添加/移除类型和成员的泛型类型参数(我是否遗漏了什么?).这不包括对成员机构的任何更改,也不包括对私有成员的任何更改(即,我们不考虑反映).
Binary-level break-API更改会导致根据旧版本的API编译的客户端程序集可能不会随新版本一起加载.示例:更改方法签名,即使它允许以与以前相同的方式调用(即:void以返回类型/参数默认值重载).
Source-level break-一个API更改,导致编写的现有代码针对旧版本的API进行编译,可能无法使用新版本进行编译.然而,已经编译的客户端程序集仍能像以前一样工作.示例:添加一个新的重载,这可能会导致以前明确的方法调用出现歧义.
Source-level quiet semantics change-一个API更改,导致编写的现有代码针对较旧版本的API悄悄地更改其语义,例如通过调用不同的方法.但是,代码应该继续编译,没有警告/错误,以前编译的程序集应该像以前一样工作.示例:在现有类上实现新接口,导致在重载解析期间 Select 不同的重载.
最终目标是对尽可能多的 destruct 性和安静的语义API更改进行编目,并描述 destruct 的确切影响,以及哪些语言受其影响,哪些语言不受其影响.对后一种语言进行扩展:虽然有些更改会普遍影响所有语言(例如,向接口添加新成员会 destruct 该接口在任何语言中的实现),但有些更改需要非常特定的语言语义才能发挥作用,以获得突破.这通常涉及方法重载,通常与隐式类型转换有关.即使对于符合CLS的语言(即至少符合CLI规范中定义的"CLS使用者"规则的语言),这里似乎也没有任何方法来定义"最小公分母"——尽管如果有人在这里纠正我的错误,我将不胜感激,所以这将不得不逐个语言.最感兴趣的自然是随之而来的.开箱即用: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#没有被 destruct ,因为它没有任何语言级别的重载运算符支持,无论是显式还是隐式的,都必须作为op_Explicit
和op_Implicit
方法直接调用.
添加新的实例方法
种类:源代码级别的安静语义更改.
受影响的语言: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#没有被 destruct ,因为它没有ExtensionMethodAttribute
的语言级支持,并且需要将CLS扩展方法称为静态方法.