早期和晚期的约束力
当C#中的早/晚绑定发生时,我试图让我的头脑发生变化。
非虚方法总是早绑定的。 虚拟方法总是迟到:编译器插入额外的代码来parsing在执行时绑定的实际方法,并检查types安全性。 所以亚型多态使用后期绑定。
使用reflection调用方法是后期绑定的一个例子。 我们编写代码来实现这一点,而不是编译器。 (例如调用COM组件。)
VB.NET在Option Strictclosures时支持隐式后期绑定。 当一个对象被赋值给一个被声明为Objecttypes的variables时,这个对象是延迟绑定的。 VB编译器插入代码以在执行时绑定到正确的方法,并捕获无效的调用。 C#不支持此function。
我正朝着正确的方向走吗?
那么调用委托并通过接口引用调用方法呢? 这是早期还是晚期的约束?
除非你通过Reflection接口,否则一切都早于C#。
早绑定意味着在编译时find目标方法,并创build将调用此方法的代码。 无论是虚拟还是不虚拟(意味着在通话时find它的额外步骤都是无关紧要的)。 如果方法不存在,编译器将无法编译代码。
后期限意味着在运行时查找目标方法。 通常使用方法的文本名称来查找它。 如果方法不在那里,砰的一声。 程序将在运行时崩溃或进入一些exception处理scheme。
大多数脚本语言使用后期绑定,并且编译语言使用早期绑定。
C#(版本4之前)不会延迟绑定; 他们可以使用reflectionAPI来做到这一点。 该API编译为通过在运行时search程序集来查找函数名称的代码。 如果Option Strictclosures,VB可以延迟绑定。
绑定通常会影响性能。 因为后期绑定需要在运行时查找,所以通常意味着方法调用比早期绑定的方法调用要慢。
对于正常的函数,编译器可以在内存中计算出它的数字位置。 然后当它被调用的时候,它可以产生一个指令来调用这个地址的函数。
对于具有任何虚拟方法的对象,编译器将生成一个v-表。 这本质上是一个包含虚拟方法地址的数组。 每个具有虚拟方法的对象都将包含由编译器生成的隐藏成员,即v-表的地址。 当一个虚拟函数被调用时,编译器会计算出v表中相应方法的位置。 然后,它将生成代码来查看对象v-table,并在此位置调用虚拟方法。
所以,有一个虚拟function发生查找。 这是非常优化的,所以它会在运行时很快发生。
早绑定
- 编译器可以确定编译时调用函数的位置。
- 编译器可以保证在程序运行之前(在任何程序运行之前)该函数将存在并且可以在运行时被调用。
- 编译器保证函数采用正确数量的参数,并且它们是正确的types。 它还检查返回值的types是否正确。
后期绑定
- 查找将花费更长的时间,因为它不是一个简单的偏移量计算,通常会进行文本比较。
- 目标函数可能不存在。
- 目标函数可能不接受传递给它的参数,并且可能具有错误types的返回值。
- 通过一些实现,目标方法实际上可以在运行时改变。 所以,查找可能会执行一个不同的function。 我认为这发生在Ruby语言中,您可以在程序运行时在对象上定义一个新的方法。 后期绑定允许函数调用开始调用方法的新重写,而不是调用现有的基方法。
C#3使用早期绑定。
C#4使用dynamic
关键字添加了后期绑定。 有关详细信息,请参阅Chris Burrow关于此主题的博客文章 。
至于虚拟方法和非虚拟方法,这是一个不同的问题。 如果我调用string.ToString()
,则C#代码绑定到虚拟object.ToString()
方法。 调用者的代码不会根据对象的types进行更改。 而是通过一个函数指针表来调用虚拟方法。 对象的一个实例是指对象的表指向它的ToString()
方法。 一个string的实例有虚拟方法表指向它的ToString()
方法。 是的,这是多态。 但不是迟到的约束。
在大多数情况下,早期绑定是我们每天做的事情。 例如,如果我们在编译时有一个Employee
类,那么我们只需创build该类的实例并调用任何实例成员。 这是早期的约束。
//Early Binding **Employee** employeeObject = new **Employee**(); employeeObject.CalculateSalary();
另一方面,如果你在编译时没有这个类的知识,那么唯一的办法就是用reflection来延迟绑定。 我遇到了一个很好的video解释这些概念 – 这是链接 。
简单来说,早期绑定发生在编译时,编译器有关于types及其所有成员的知识,后期绑定发生在运行时,编译器不知道关于types和成员的任何信息。 我在YouTube上遇到了一个很好的video,解释了这些概念。
http://www.youtube.com/watch?v=s0eIgl5iqqQ&list=PLAC325451207E3105&index=55&feature=plpp_video
这是一个非常古老的职位,但想增加更多的信息。 当你不想在编译时实例化对象时使用后期绑定。 在C#
您使用Activator
在运行时调用绑定对象。
早期绑定
该名称本身描述了编译器知道它是什么types的对象,它包含的所有方法和属性是什么。 只要你声明了这个对象,.NET Intellisense就会通过单击点button来填充它的方法和属性。
常见示例:
comboboxcboItems;
ListBox lstItems; 在上面的例子中,如果我们inputcboItem并放置一个点,它会自动填充combobox的所有方法,事件和属性,因为编译器已经知道它是一个combobox。
晚绑定
该名称本身描述了编译器不知道它是什么types的对象,它包含的所有方法和属性是什么。 您必须将其声明为对象,稍后需要获取对象的types以及存储在其中的方法。 一切都将在运行时间知道。
常见示例:
对象objItems;
objItems = CreateObject(“DLL或程序集名称”); 这里在编译期间,objItems的types不确定。 我们正在创build一个dll的对象,并将其分配给objItems,所以一切都在运行时确定。
早绑定与晚绑定
现在进入照片了
应用程序将在Early绑定中运行得更快,因为在这里没有装箱或拆箱。
更容易在早期绑定中编写代码,因为智能感知将自动填充
早期绑定中的最小错误,因为在编译时间本身检查语法。
后期绑定将支持所有types的版本,因为一切都在运行时决定。
如果使用了“延迟绑定”,则代码在将来增强function中的影响最小。
性能将在早期绑定代码。 两者都有优点和缺点,开发者决定根据场景select合适的绑定。
本文是构build.net组件的指南,在运行时使用Vb6项目中的后期绑定,附加事件并获得callback。