VB刚出现时就是晚绑定语言,没有任何类型。晚绑定对VB有某种核心作用。而后,VB已逐步演进为一种更“强类型”的语言,到现在,甚至可以把VB看作一种支持晚绑定的强类型语言。

C#从一开始就是强类型语言,直到现在都坚持早绑定。对于晚绑定,C#只是一种选择,可能以不同于VB的方式来做而且会有所改进。对于老式的弱类型对象模型来说,比如OLE,如果从晚绑定角度出发,会比从早绑定好讨论,因为这种对象模型无非就是对象若干方法的交互。

当你查看一个大函数内部嵌套很深的结构,比如FOR循环时,语言是何时,如何处理变量捕获、如何进行实例保护就非常不同。在C#中,每次循环时实例都被保护,而VB有点像JavaScript,变量被隐性提升到函数顶部。所以,在变量捕获方面也存在语义上的区别。有时这些区别及其细微,必须用非常变态的程序才能观察到。

LINQ, 函数型语言风格,所有的东西都基于表达式。“表达式”从其定义来说就是可组合的。不断提高程序员的生产率:提升抽象的层次——垃圾回收机制,类型安全,异 常处理,全新的“声明型”编程语言等。声明型语言获得了更高层次的“可组合性”。当我们更多的使用“函数型”或者“声明型”风格的编程时,更有可能把运行 时框架构建得能更好的发挥多核的优势,更好的处理并发。如果以“命令型”风格来工作,能发挥的余地就很小,因为无法预见所有动作,必须串行执行否则不可预 料。

CLR以 及目前绝大多数的运行时都是“命令型”引擎,指令都相当传统,比如堆栈增长;它们拥有易变的状态,包括易变的全局状态等等。在此之上,之所以能进行“函数 型”编程,是因为“函数型”编程本质上是“命令型”编程所具备的能力集的一个子集。最大化这种灵活性,使“函数型”能力子集越来越相关和主流化。

“函数型”语言是“串行执行”的好药方。要想使“函数型”语言运转良好,关键点并不是处理好基本的表达式问题,而是处理好lambda表达式和副作用的问题,使能够将表达式作为第一级的编程要素来使用,能够指出lambda表达式和Closure(函数型编程语言中的概念,可以方便组合函数,返回函数)的副作用。

“动态类型”和“隐式类型”的区别:一种情况是,靠编译器推断出类型,但编译器在编译期就推断出来了。另一种情况是,编译器在编译时一无所知,它假设是任何类型,然后在运行时的适当时机,检查到底是什么类型。因为在默认情况下推断本地变量声明的类型,所以无论 Option Strict 的设置为何,总是早期绑定对于这些变量的访问。在 Visual Basic 9.0 中,程序员必须按以下方式将变量显式声明为类型 Object,从而显式指定晚期绑定:要求使用显式晚期绑定是为了防止意外使用晚期绑定,但更重要的是,这样做可以有力地扩展它对诸如 XML 等新数据类型的晚期绑定。

新的 Visual Basic 9.0 对象初始值设定项 采用的是一种基于表达式的 With 格式,用于以简明的方式创建复杂的对象实例。通过对象初始值设定项,我们能够将以上两条语句捕获为一条(隐式类型的)本地声明。这种在表达式中进行的对象初始化对于查询而言非常重要。一条查询语句通常就像由等号右侧的 Select 子句初始化的对象声明。由于 Select 子句返回一个表达式,因此我们必须能够以一条表达式初始化整个对象。任何支持 Add 方法的集合都能够通过一个集合初始值设定项 表达式进行初始化。

  动态语言今年来发展很快,各种脚本语言多少都带有些动态语言的特点。动态语言以其灵活的语法和丰富的运行时行为赢得了许多人的青睐。在.NET阵营,C#一直扮演着静态语言的角色,尽管3.0的语法改变很激进,但仍注重于编译时的类型检查和约束。动态特性用的不好会产生更多运行时问题,不易确保程序的可靠性,但其提高开发效率的作用是毋庸置疑的。Visual Basic 9.0是Visual Studio中唯一能让你统领动态和静态两大领域的语言,让你在程序中自由选择喜欢的风格。

  我们知道Object没有Add或RemoveAt方法,但运行时类型ArrayList具有他们,因此Visual Basic允许到运行时再检查有无相应的操作并支持。既然这个过程已经是在运行时做的了,我们就应该允许这个后期绑定的操作本身也是在运行时确定。这个语法增强叫做动态标识符。

注意在:=符号之前的大括号,表示对参数名称的动态结合。有了动态标识符这一特性,Visual Basic 9.0将不需要利用反射的复杂语法,就可以做很多需要反射和运行时类型信息来做的任务,这使得Visual Basic成为解决你手边小问题的最佳帮手。

在隐式类型的局部变量声明中,局部变量的类型是通过局部声明语句右侧的初始值设定项表达式推断的。推断类型可防止意外使用后期绑定,更重要的是,它允许为新数据类型(如 XML)绑定强大扩展。局部变量类型推测:不要担心性能问题;它是编译时由编译器进行推测的,是一种强类型的特性。 同时,VB 9还支持For(For Each)的循环变量推测,无需再临时定义循环变量。

对象初始化器: 对象初始化器是一项重要的语法增强,它对于Coding有着莫大的帮助。我们知道,在Visual Basic 8及以前版本中,必须用属性逐一赋值的方式来创建一个类。而在Visual Basic 9中,一切都不同了:

后期绑定:若将一个变量声明为 As Object 或 As Variant(包括 As Form 或 As Control 的变量),Visual Basic 在编译时就无法确定该变量将引用哪种类型的对象。因而,Visual Basic 必需使用后期绑定,在运行时确定对象的属性和方法能否使用该变量。

若使用后期绑定,则每次调用属性或方法时,Visual Basic 都要将成员名传给该对象 IDispatch 接口的 GetIDsOfNames 方法。GetIDsOfNames 返回该成员的派遣 ID,或 DispID。Visual Basic 再将该 DispID 传给 IDispatch 接口的 Invoke 方法来调用该成员。

对进程外部件而言,这意味着一次额外的跨进程方法调用,结果是调用开销翻番。
       前期绑定:要是在编译时 Visual Basic 能够知道属性或方法所属的对象,就可以预先查找该成员在类型库中的 DispID 或 vtable 地址。这样就无须在运行时调用 GetIDsOfNames。
       当显式声明了变量的类时,例如 As Widget,该变量就只能存放该类的对象的引用。Visual Basic 就可认为该变量调用的所有属性和方法使用前期绑定。
       建议在 Visual Basic 和应用程序中使用这种方法来声明对象变量。
       使用前期绑定还是后期绑定完全取决于声明变量的方式。对象的树立方式对此没有任何影响。
       后期绑定的几个优势和好处
  第一,个人以为,由于VB6不支持实现继承,对于某些设计,可以使用将对象定义为Variant变量,而获取某些设计和编码上的便利,而得到接口或抽象类的好处。这样,无须继承机制,也可以得到抽象接口的优势,而使接口、实现分离。

  第二,在调用外部的COM自动化组件时,如Office,要是通过这种方式调用,对于不同版本的Office,要是你调用的方法、属性都是存在的,那么可以适应不同版本的Office,但要是通过前期绑定,在项目引用中确定对象类型,是有版本兼容问题的。

效率和劣势

其实最主要的劣势是效率问题,《Advanced Visual Basic 6》一书说,使用Variant变量和Long变量进行循环,效率差别是1.5倍,而没有他人以为的那么大,而且对于大对象,差异也不是很大。对于本文前边的例子,要是建立的是进程内对象,前期绑定和后期绑定调用效率区别大概2:3左右,也就是说也是1.5倍。对于调用Office这样的外部COM自动化对象,也许区别大一些,没有专门测试,不过对于Office自动化,速度主如果决定于Office本身的启动、初始化。

另外一个劣势是没有了IDE下的属性、方法成员自动列出。

所以,个人以为,在使用VB6的时候,为了得到好的设计,有时不妨使用一些VB6的后期绑定的特点,来提高设计质量。

早期绑定联系由编译器在根据.NET源 代码创建程序集的期间创建。我们无法为一个虚方法或抽象方法创建一个早期绑定。事实上,当一个虚方法或抽象方法被调用时,多态机制会在执行期间根据被调用 方法的实际对象确定将要执行的代码。这种情况下,该联系被视为动态绑定。在其他资料中,动态绑定有时被称为隐式的后期绑定,因为它们是由多态机制隐式创建 的并且是在执行期完成的。

现在让我们进一步观察早期绑定,它们是为静态方法或类中那些不是虚方法或抽象方法的方法创建的。如果严格遵循前一节中对“类的联系”的定义,.NET中是不存在早期绑定的。事实上,我们必须先等待JIT编译器将方法体转换为机器语言,才能知道它在进程地址空间中的物理地址。创建程序集的编译器并不知道这个方法的地址信息[1]。为了解决这个问题,创建程序集的编译器在IL代码中方法将被调用的位置插入了与被调用的方法相对应的元数据符号(metadata token) 。当方法体被即时(JIT)编译的时候,CLR在内部保存了方法与机器语言下的方法体的物理地址的对应联系。这段被称为存根的信息被物理保存到一个与方法相关的内存地址中。

以上的认识很重要,因为在像C++这样的语言中,当一个方法不是虚方法或抽象方法(即C++中的纯虚函数)时,编译器就可以计算出该方法体在机器语言下的物理地址。然后,编译器在每个调用该方法的位置插入一个指向该内存地址的指针。这个区别给了.NET很大的优势,因为编译器不需要再考虑诸如内存表现之类的技术细节。IL代码完全独立于它所运行的物理层。

而在动态绑定中,其中几乎所有的事物都是以与早期绑定中相同的方式工作的。编译器在IL代码中方法被调用的位置插入了与被调用的虚(或抽象)方法相对应的元数据符号。这里,我们提到的元数据符号是属于定义在引用类型中的方法的,而该引用类型就是将发生方法调用的那个类型。然后就是CLR的工作,它将在执行期间根据引用对象的具体实现确定跳转到哪个方法。

插入一个类型元数据符号,编译器使用这项技术创建动态绑定与早期绑定,它主要用于以下三种情况。

  1. 当包含在模块中的代码调用了一个处在同一模块中的方法时。
  2. 当包含在模块中的代码调用了一个处在同一程序集的不同模块中的方法时。
  3. 当包含在程序集的一个模块中的代码调用了定义在另一个在编译期引用进来的程序集中的方法时。在运行时,如果即时编译方法调用的时候该程序集尚未载入,那么CLR将隐式地装载它。

后期绑定在微软的开发世界中并不是什么新的概念。COM技术中的自动化机制就是一个例子,它使用IDispatch接口作为变通方法,允许脚本语言或者弱类型的语言如VB使用后期绑定。后期绑定的概念同样存在于Java中。 后期绑定是习惯于C++的开发者很难理解的概念之一。事实上,在C++中只存在早期与动态绑定。难于理解的原因来自以下事实:我们知道创建一个绑定所需的必要信息(即元数据符号)处在将被调用的类所在的程序集B之中,但是我们不能理解为什么开发者不能利用编译器的能力,在编译A的期间,通过引用程序集B创建早期与动态绑定。对此,存在以下解释:
       最常见的原因在于某些语言根本就没有编译器!在一个脚本语言中,指令是被一条一条解释的。在这种情况下,只存在后期绑定。通过使用后期绑定,可以使用由解释型语言编译的程序集中的类。在.NET中可以方便地使用后期绑定技术这一事实,使得创建一个专有的解释/动态语言变得相对容易(比如IronPython语言http://www.ironpython.com/)。

我们可能希望在由编译型语言如C#写成的程序中使用后期绑定技术。原因在于,使用后期绑定可以为应用程序的通用架构带来某种程度的灵活性。该技术实际上是一种最近很流行的被称为插件的设计模式,我们将在本章对它做进一步介绍。

某些应用程序需要调用尚未获得的程序集中的代码。一个典型的例子就是开源工具NUnit,该工具可以通过调用任意一个程序集的方法来测试其代码。我们将在稍后构造一个自定义attribute的时候,再进一步接触这个话题。

如果在程序集A编译期间程序集B尚不存在,我们就必须在A中的代码与B中的类之间使用后期绑定。这种情况我们将在稍后谈到动态构造程序集的时候介绍。

一些人喜欢使用后期绑定来代替多态。事实上,因为在调用期间,只考虑方法的名称与签名式,而与被调用方法所处对象的类型无关,所以只需要在实现对象的时候提 供具有合适名称和签名式的方法即可。但是,我个人不推荐这种做法,因为它的约束性太差,并且无法促使应用程序的开发者去做恰当的设计以及使用抽象接口。

除了刚提到的原因外,还有就是不需要显式地使用后期绑定。不要为了好玩而在应用程序中使用后期绑定,因为:会失去由编译器完成的语法验证的好处。后期绑定的性能远不如早期或动态绑定方法。(即使使用了后面提到的优化方法。) 无法为被混淆的类创建后期绑定。事实上,在混淆过程中,程序集中包含的类的名称会被改变。因此,后期绑定机制无法正确地找到合适的类。

转载于:https://www.cnblogs.com/brunoyu/archive/2009/07/18/1526124.html

一次公司内部的Tech Talk中涉及到的关于语言的发展问题相关推荐

  1. 使用 satis 搭建一个私有的 Composer 包仓库 在我们的日常php开发中可能需要使用大量的composer包,大部份都可以直接使用,但在公司内部总有一小部份包是不能公开的,这时候我们就需

    使用 satis 搭建一个私有的 Composer 包仓库 在我们的日常php开发中可能需要使用大量的composer包,大部份都可以直接使用,但在公司内部总有一小部份包是不能公开的,这时候我们就需要 ...

  2. 从指标管理中获取洞察,赋能公司内部论坛社区运营

    本文作者:张起楠 做了运营的同事多多少少都有这样的感觉,不断在公司内发起各项活动和话题,希望能够调动员工参与度,虽然每天投入大量的时间,但却无法确定真实的活动效果.在信息爆炸的时代,我们可以轻松接触到 ...

  3. ID Tech 5 中 Megatexturequot;针对地形的D3D9 基本实现原理

    http://blog.csdn.net/BoYueJiang/article/details/8908373 ID Tech 5 中"Megatexture"针对地形的D3D9  ...

  4. ID Tech 5 中Megatexture针对地形的D3D9 基本实现原理

    ID Tech 5 中"Megatexture"针对地形的D3D9 基本实现原理 ID Tech 5 中"Megatexture"针对地形的D3D9 基本实现原 ...

  5. ID Tech 5 中quot;Megatexturequot;针对地形的D3D9 基本实现原理

    ID Tech 5 中"Megatexture"针对地形的D3D9 基本实现原理 姚勇 H3D 2007-8 本文对ID SOFTWARE 使用的"megatexture ...

  6. 从阿里孵化钉钉谈起,大公司内部创业到底有多难?

    近日,在华为内部论坛上,一则关于<为什么阿里出现了"钉钉",我们没有?>的帖子引起热议. 围绕该主题,一大批的华为员工在论坛上探讨了华为产品设计.创新氛围,以及大企业内 ...

  7. 一个老鸟发的公司内部整理的 Android 学习路线图 Markdown 版本

    jixiaohua发了一篇一个老鸟也发了一份他给公司内部小伙伴整理的路线图.另一份 Android 开发学习路线图.可惜不是MarkDown格式的,所以jixiaohua直接上传的截图,在jixiao ...

  8. IBM 计划在公司内部推行基于比特币的开源项目Hyperledger

    目前,比特币仍然会让人联想到地下毒品市场的形象,想象成无政府主义黑客一心想从金融公司中拿到资金.但是,世界上一些大型的公司正在拥抱这种加密货币背后的技术. 去年,一批科技和金融巨头,包括 IBM.英特 ...

  9. YUM更换源(1)--yum找不到安装包 2013-01-18 20:08 8687人阅读 评论(1) 收藏 举报 分类: linux(70) 公司提供的CentOS VM中,/etc/yum.r

    YUM更换源(1)--yum找不到安装包 2013-01-18 20:08 8687人阅读 评论(1) 收藏 举报 分类: linux(70) 公司提供的CentOS VM中,/etc/yum.rep ...

最新文章

  1. android自定义WaveView水波纹控件
  2. SpringMVC---数据校验
  3. 判断非负整数是否是3的倍数_二、因数与倍数教案
  4. boost::contract模块实现volatile的测试程序
  5. c++ 重载 重写_关于C/C++中的++i和i++实现机制的探讨
  6. 终于有人把数据湖讲明白了
  7. 设计灵感|C4D在海报中可以这样应用
  8. Python执行Linux系统命令方法
  9. 火爆的文字游戏你玩了吗?「GitHub 热点速览 v.22.06」
  10. 防火墙技术之安全区域
  11. HTML网页设计:导航栏
  12. 校验EXE文件防止软件被破解
  13. CA1704:标识符应正确拼写
  14. c#语言编写汉诺塔游戏,c#语言编写汉诺塔游戏
  15. java平台rpg游戏丧尸_RPG的生存游戏你玩过吗?《Dead Age》带你逃离丧尸
  16. 106句激励自我的话
  17. DNS是什么意思有什么作用了
  18. 多自由度有阻尼matlab,多自由度阻尼系统固有振型的MATLAB求解程序
  19. 2017-2018-1 20162316刘诚昊 实验二 树
  20. 败团---吴家私房菜(别有天茶艺居)

热门文章

  1. pmp每日三题(2022年2月18日)
  2. 夏季适合IT程序员的养生小妙招
  3. CPU与GPU的区别
  4. linux find 排除某目录或文件 执行
  5. 如何检查防火墙引起的端口不通
  6. Oracle 11g新特性:Automatic Diagnostic Repository
  7. SaaS全球普及面临三大门槛
  8. sort 与 sorted 区别:
  9. python学习之自习语法(20180626_update)
  10. centos6 python 安装 sqlite 解决 No module named ‘_sqlite3′