除非您通过反射接口,否则一切都在 C# 中早期绑定。
早期绑定只是意味着在编译时找到目标方法,并创建将调用它的代码。它是否是虚拟的(这意味着在调用时需要额外的步骤来找到它是无关紧要的)。如果该方法不存在,编译器将无法编译代码。
后期绑定意味着在运行时查找目标方法。通常使用方法的文本名称来查找它。如果方法不存在,砰。程序将在运行时崩溃或进入一些异常处理方案。
大多数脚本语言使用后期绑定,而编译语言使用早期绑定。
C#(版本 4 之前)没有后期绑定;然而,他们可以使用反射 API 来做到这一点。该 API 编译为通过在运行时挖掘程序集来查找函数名称的代码。如果 Option Strict 关闭,VB 可以后期绑定。
绑定通常会影响性能。因为后期绑定需要在运行时查找,这通常意味着方法调用比早期绑定方法调用慢。
对于普通函数,编译器可以计算出它在内存中的数字位置。然后它在调用函数时可以生成一条指令来调用该地址处的函数。
对于具有任何虚方法的对象,编译器将生成一个 v-table。这本质上是一个包含虚拟方法地址的数组。每个具有虚方法的对象都将包含一个由编译器生成的隐藏成员,它是 v-table 的地址。当调用虚函数时,编译器会计算出相应方法在 v-table 中的位置。然后它将生成代码以查看对象 v-table 并在此位置调用虚拟方法。
因此,对虚拟功能进行了查找。这是经过高度优化的,因此它会在运行时很快发生。
早绑定
- 编译器可以在编译时计算出被调用函数的位置。
- 编译器可以尽早(在任何程序代码运行之前)保证该函数将存在并在运行时可调用。
- 编译器保证函数采用正确数量的参数并且它们是正确的类型。它还检查返回值的类型是否正确。
后期装订
- 查找将花费更长的时间,因为它不是简单的偏移计算,通常需要进行文本比较。
- 目标函数可能不存在。
- 目标函数可能不接受传递给它的参数,并且可能具有错误类型的返回值。
- 对于某些实现,目标方法实际上可以在运行时更改。因此,查找可能会执行不同的功能。我认为这发生在 Ruby 语言中,您可以在程序运行时在对象上定义一个新方法。后期绑定允许函数调用开始为方法调用新的覆盖,而不是调用现有的基方法。