简介
本文的目的,是一次都证明,经验证据的手段,由VB和C#编译器生成的MSIL代码是不相等的,特别是在处理与非void的方法和字符串值比较。为了证明这一点,对比,将每两个相同的组件,在VB编码,另外一个可能的解释为什么存在差异,在C#的编译器产生的MSIL代码之间。之后,将简要地讨论了这种差异的意义随着打算最多的VB与C#语言战争耀斑一些偏颇意见。测试程序集
在测试中使用的两个组件在所有方面都是相同的。然而,在这里我只提供一个代码,只键入每个程序集公开,以及由此产生的MSIL代码,代表只有两种方法的相同类型的揭露。为了验证其他的因素是什么??是平等的为好,如优化设置,,感觉免费下载的代码。最后,这两个组件进行编码和使用VS.NET 2003的Windows XP SP2的机器上(NET 1.1 SP1)的编制。此外,MSIL代码是使用ILDASM.EXE(版本1.1.4322.573)获得。VB型ClassLibrary1.Class1:公共类class1 的Public Sub New() END SUB
由于整数的公共函数foo1(布尔BYVAL测试)
DIM我作为整数 如果(测试),然后 I = 1
0; 其他 I = 2
60; 结束如果 回报我 端功能
公共小组foo2的(布尔BYVAL测试) &
#160; DIM作为String的=没有 如果S = String.Empty然后 结束如果 END SUB末级C#类型ClassLibrary1.Class1:公共类class1{ 公共Class1的() { } 公众诠释foo1(BOOL测试) { 诠释我;
0; (测试) I = 1;&
#160; 其他 我= 2; 返回我; } 公共无效foo2的(BOOL测试) { 字符串s = NULL; (S == string.Empty){};
160; }
所以现在我们有两个相同的类型,在VB和C#编写的,后者的书面前。首先,让我们每一个编译器产生的成员foo1比较MSIL代码。VB的MSIL(foo1):公共实例。方法INT32 foo1(BOOL测试)CIL可网管{ / /代码大小11(0xb) maxstack 1
160;当地人的init(INT32 V_0 INT32 V_1) IL_0000:ldarg.1 IL_0001:brfalse.s IL_0007 IL_0003:ldc.i4.1 IL_0004:stloc.1 IL_0005:br.s IL_0009
; IL_0007:ldc.i4.2 IL_0008:stloc.1 IL_0009:ldloc.1
0; IL_000a:RET} / / Class1的方法结束:foo1C#中的MSIL(foo1):公共hidebysig实例方法INT32 foo1(BOOL测试)CIL可网管{ / /代码大小11(0xb) maxstack 1 当地人的init(INT32 V_0)
IL_0000:ldarg.1 IL_0001:brfalse.s IL_0007 IL_0003:ldc.i4.1 IL_0004:stloc.0 IL_0005:br.s IL_0009
IL_0007:ldc.i4.2 IL_0008:stloc.0 IL_0009:ldloc.0
;IL_000a:RET} / / Class1的方法结束:foo1
乍一看,两个编译器产生的MSIL代码看起来是相同的。首先,每个版本都有相同数量的MSIL代码行其他。其次,两个版本完全相同。maxstack指令,也就是说,每个方法需要使用其他相同数量的栈槽。但是,如果你看一下在第三行MSIL代码,当地人init指令,它是用来声明变量并分配初始值,一个显着差异之间存在着两种版本:
VB:当地人的init(INT32 V_0,INT32 V_1)
C#中:当地人的init(INT32 V_0)
为什么,尽管方法foo1使用一个,只有一个本地变量(i),VB MSIL代码声明并初始化一个额外的变量,变量V_0,这是从来没有使用过?另一方面,C#的MSIL代码声明并初始化之一,只有一个变量,这使得绝对意义上已经表示明显的原因。
现在的问题是,为什么差距,无论多么重大的或微不足道的,它可能是。 IM没有专家,特别是在处理与MSIL,但我几乎是100%肯定的,未使用的变量是只有因为,不像C#,VB允许一个功能的代码路径没有返回值,而当这种情况发生,未使用V_0变量成为使用。换句话说,在VB中,可以有一定的回报类型的功能,但如果你不显式地返回该类型的值,编译器将返回类型的默认值,因此,存在的神秘V_0变量。为了证明我的观点,让注释掉value.Public功能foo1 VB版本的foo1方法,明确返回功能(布尔BYVAL测试线)作为整数的最后一行
DIM我作为整数 如果(测试),然后 I = 1 其他
; I = 2 结束如果
0; "回报我端功能
经过上述变化和编译,生成的MSIL代码看起来:公共实例方法INT32 foo1(BOOL测试)CIL管理{ / /代码大小11(0xb) maxstack 1
当地人的init(INT32 V_0 INT32 V_1) IL_0000:ldarg.1 IL_0001:brfalse.s IL_0007 IL_0003:ldc.i4.1 IL_0004:stloc.1 IL_0005:br.s IL_0009
60;IL_0007:ldc.i4.2 IL_0008:stloc.1 IL_0009:ldloc.0
160;IL_000a:RET} / / Class1的方法结束:foo1
的VB foo1 MSIL代码的两个版本之间唯一的区别是在倒数第二行。第一个版本,它明确地返回一个值,压入堆栈变量V_1,通过ldloc.1,因为V_1代表可变的,我认为,这反过来又明确返回值。第二个版本,doesn't明确返回一个值,因此,在编译器的结果压入堆栈的变量V_0,它始终坚持的函数的返回类型的默认值,由教学ldloc手段。 0。
这样的故事在这里的道德是,对于任何非空白VB编写的方法,编译器会生成MSIL代码总是声明和一个额外的相同类型的局部变量初始化为包含它的功能,一个变量可能或可能无法使用,这取决于是否功能不明确返回值分别。这里是我个人的看法,虽然额外的变量是尊重其性能和内存消耗的影响微不足道,但VB编译器应该足够聪明,包括额外的变量,当且仅当,成员的代码路径没有返回值。如果确实如此,那么额外的变量的声明和初始化毫无疑问是毫无意义的。
现在,让我们继续前进,在MSIL代码看看VB和C#编译器生成的方法foo2的。VB的MSIL(foo2的):公共实例方法无效foo2的(BOOL测试)CIL管理{ / /代码大小18(0X12) maxstack 3 当地人的init(字符串V_0) IL_0000:ldnull IL_0001:stloc.0 IL_0002:ldloc.0 IL_0003:ldsfld字符串[0] System.String::空 IL_0008:ldc.i4.0 IL_0009:INT32调用[Microsoft.VisualBasic] Microsoft.VisualBasic。 &
#160; CompilerServices.StringType::STRCMP(字符串,
字符串,
BOOL) IL_000e:ldc.i4.0 IL_000f:bne.un.s IL_0011 IL_0011:RET} / / Class1的方法结束:foo2的C#的MSIL(foo2的):公共hidebysig实例方法无效foo2的(BOOL测试)CIL管理/ /代码大小15(0xF的) maxstack 2 当地人的init(字符串V_0) IL_0000:ldnull IL_0001:stloc.0 IL_0002:ldloc.0 IL_0003:ldsfld字符串[0] System.String::空
IL_0008:调用BOOL [0] System.String:op_Equality(字符串,
; 字符串) IL_000d:流行 IL_000e:RET} / / Class1的方法结束:foo2的
好了,它只是快速浏览的方法foo2的生成MSIL代码的两个版本,确实存在差异明显,此外,明显的差异比更是与foo1的情况下。
首先,比较每个版本的代码大小的意见,其明确的,更多的MSIL代码是用VB版本比C#版本(/ /代码大小15(/ /代码大小18(0X12))( 0xF的))。
二,VB版本预计将使用三个栈槽(maxstack 3),而C#版本预计将只使用两个栈槽(maxstack 2)。
从那里开始,所有仍然相等,直到我们到达IL_0008行,两个版本在这一点大大偏离。
C#版本首先推入堆栈的布尔结果[0] System.String呼叫:op_Equality,这是函数的C#使用比较字符串值时使用==运算符。然后,它会立即删除(POP)从堆栈权给调用者返回之前执行这个相同的布尔值。虽然去年的流行似乎毫无意义,theres此事真的没有选择,因为一个方法评估堆叠必须保留控制权返回给调用者之前空,除非是要返回一个值,是与非void的方法。
另一方面,VB版本先压入堆栈值0(ldc.i4.0),随后将弹出堆栈调用的一个参数,以Microsoft.VisualBasic.CompilerServices.StringType :STRCMP,这是函数VB使用比较字符串值时使用=操作符,这是入栈的整数结果。一旦多数民众赞成,指令ldc.i4.0再次使用入栈值0,所以,它可能是随后相比StrComp的整数结果。然后,通过指令bne.un.s IL_0011,最后两个入栈值,即,STRCMP和ldc.i4.0调用的结果,弹出,比较,如果不平等的结果,执行转移到IL_0011的指令,这似乎是因为冗余指令IL_0011紧随无论与否的结果是不平等,但最有可能是为了从堆栈中弹出的仍然留在它的最后两个值。
所以再次,问题就变成,为什么差距,无论多么重大的或微不足道的可能。那么,在这种情况下,答案是简单明了。 VB是为了向后兼容的原因,被迫使用strcmp,而不是String:op_Equality,其结果更激烈的STRCMP认为一个空字符串和空字符串相等,这是不是有很大的不同,弦乐:op_Equality,此外,这是最有可能的主要原因,前者是后者,而不是使用。从纯性能的角度来看,弦乐:op_Equality到strcmp优越的性能提升虽然会显现出来,只有当一个字符串比较激烈是,也许是一个紧密的循环内作出的。此外,还有一个简单的解决方案,这将消除这一案件中的问题,最大的性能是必须的,而不是=运算符比较字符串值时,使用String.Equals或op_Equality。例如,改变了foo2的VB版本:公共子foo2的(布尔BYVAL测试)
DIM作为String的=没有 如果String.op_Equality(S,String.Empty) 结束如果END SUB管理
在以下MSIL代码的结果:公共实例方法无效foo2的(BOOL测试)CIL{
/ /代码大小16(0x10的) maxstack 2 当地人的init(字符串V_0) IL_0000:ldnull IL_0001:stloc.0 IL_0002:ldloc.0 IL_0003:ldsfld字符串[0] System.String::空
0;IL_0008:调用BOOL [0] System.String:op_Equality(字符串,
字符串) IL_000d:brfalse.s IL_000f IL_000f:RET} / / Class1的方法结束:foo2的
请注意,现在的MSIL代码的两个版本是相同的,除了第二个到最后一个指令,。 C#版本只是弹出的协议栈的最后值保持它,通过POP指令,而在VB的版本弹出关闭堆栈上的最后一个值,零比较,和如果平等的存在,将控制权转移指令IL_000f,所有,在这种情况下似乎是多余的,因为原来的语句块,如果是空的,因此编译器应该足够聪明,忽略它虽然另一方面,通过brfalse.s L_000f指令,编译器也足够聪明要知道,在大多数,如果不是所有的情况下,如果语句块不会是空的,因此,大概的数字,为什么甚至懒得尝试检测一个。测试结果的意义
你可能有在读这篇文章,我是想证明一个观点一个C#程序员后得出的结论。好了,你说对了一半。我一定努力证明一个点,点是,与VB语言,您如何使用的语言,与遗留代码的向后兼容性,和逻辑假设的内在本质的原因,在无为而治的结果VB编译器生成的代码几乎是C#编译器的效率,但不作为一个高效的C#编译器生成代码。
(注:偏见的陈述,旨在促进VB与C#语言的战争即将开始,所以你可能要停止阅读。)
在说,让我说得很清楚,我做我在VB中的当务之急编码,自从我有我在MIS中获得学士学位后,我的第一份工作。一个优秀的语言,因为第4版,在更大程度上,与第7版(NET)起,不限制到一个单一的编程范式的方式C#不的程序员。关于MSIL代码的差异,本文的重点,在地球上真的除了鄙视(CG)的VB程序员关心的意义?当然,乡亲,支付给我们的代码可以不在乎所有本文中发了言,我向你保证,如果我是试卖的情况下,C#是更好吗??比VB基于什么在这一个CIO / CTO,知道他的。NET的文章,我可能会被解雇我缺乏完整的商业判断。此外,吉姆,财务副总裁,MSIL代码多数民众赞成在这篇文章中包括和尝试,使他的部门VB应用程序都应该在C#中重建的情况下,我保证你会笑本赛季的股票,虽然一些C#乡亲在这里,一个特殊的,勇于尝试这样的东西。
真的,一个和唯一的原因IVE写这篇文章只是抛出的VB与C#战争的火焰汽油。 IM生病和厌倦听到所有的所有的言辞。NET语言中都是平等的,,因为这是情况并非如此,毫无疑问优于C#中的VB。此外,我也怜悯所有可怜的前提下,是如此轻易否定的,是用来支持奇谈怪论,C#是"更好"比VB。喜欢它太罗嗦的事情吗??或太牛了VB代码存在??只是不削减它。如果你开始在CP或任何一个C#与VB的辩论,请务必给我的链接,这样我可以参加。
,请不要把我所有的垃圾谈话严重。我尊重你们。这只是我零的C#语言。这只是另一种RAD工具,仅此而已,无所不及,有幸利用关闭的经验,好的和坏的,其他各种语言,包括VB,和,此外,不必担心现有的遗留代码。我的态度很可能会改变MS Office是完全用C#编写的一天。最后的思考
最后,我相当有信心,我作出的MSIL代码生成的C#和VB编译器之间的比较结论,大部分是真实的。但是,正如我已经提到,我不是专家,但如果你是知道的东西,我不能够探测到我的错误,请让我知道。