October 2005 - Posts

Want a GMail invite?

I have 50 GMail invites, so if you are interested, just post your e-mail as a comment here.

Differences between VB.NET and C# generated IL

I have been comparing the IL generated by csc.exe and vbc.exe and could see that there are some differences between them.

C#:

using System;

namespace CSharpTest
{
class Program
{
static void Main(string[] args)
{
int i = 1;
for (i = 1; i
{
Console.WriteLine("Rad {0}", i);
}
Console.ReadLine();
}
}
}

VB.NET:

Imports System

Namespace VBTest
Class Program
Shared Sub Main(ByVal args() As String)
Dim i As Integer = 1
For i = 1 To 100
Console.WriteLine("Rad {0}", i)
Next
Console.ReadLine()
End Sub
End Class
End Namespace

Both snippets are doing the same thing.

When you compile these with csc.exe and vbc.exe and, after that, decompile them with ildasm you get this:

IL generated by C#:

.namespace CSharpTest
{
.class private auto ansi beforefieldinit Program
extends object
{
.method public hidebysig specialname rtspecialname instance void .ctor() cil managed
{
// Code Size: 7 byte(s)
.maxstack 8
L_0000: ldarg.0
L_0001: call instance void object::.ctor()
L_0006: ret
}

.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code Size: 38 byte(s)
.maxstack 2
.locals init (
int32 num1)
L_0000: ldc.i4.1
L_0001: stloc.0
L_0002: ldc.i4.1
L_0003: stloc.0
L_0004: br.s L_001a
L_0006: ldstr "Rad {0}"
L_000b: ldloc.0
L_000c: box int32
L_0011: call void [mscorlib]System.Console::WriteLine(string, object)
L_0016: ldloc.0
L_0017: ldc.i4.1
L_0018: add
L_0019: stloc.0
L_001a: ldloc.0
L_001b: ldc.i4.s 100
L_001d: ble.s L_0006
L_001f: call string [mscorlib]System.Console::ReadLine()
L_0024: pop
L_0025: ret
}

}
}

IL generated by VB.NET:

.namespace VBTest
{
.class private auto ansi Program
extends object
{
.method public specialname rtspecialname instance void .ctor() cil managed
{
.custom instance void [mscorlib]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor()
// Code Size: 7 byte(s)
.maxstack 8
L_0000: ldarg.0
L_0001: call instance void object::.ctor()
L_0006: ret
}

.method public static void Main(string[] args) cil managed
{
.custom instance void [mscorlib]System.STAThreadAttribute::.ctor()
.entrypoint
// Code Size: 36 byte(s)
.maxstack 2
.locals init (
int32 num1)
L_0000: ldc.i4.1
L_0001: stloc.0
L_0002: ldc.i4.1
L_0003: stloc.0
L_0004: ldstr "Rad {0}"
L_0009: ldloc.0
L_000a: box int32
L_000f: call void [mscorlib]System.Console::WriteLine(string, object)
L_0014: ldloc.0
L_0015: ldc.i4.1
L_0016: add.ovf
L_0017: stloc.0
L_0018: ldloc.0
L_0019: ldc.i4.s 100
L_001b: ble.s L_0004
L_001d: call string [mscorlib]System.Console::ReadLine()
L_0022: pop
L_0023: ret
}

}
}

There aren´t so much differences between them, but some lines are different:

* C# uses [b]hidebysig[/b] which isn´t necessary since our class doesn´t inherit any other classes, why?
* C# uses [b]beforefieldinit[/b] since there aren´t a static constructor.
* VB.NET has two unnecessary instances to [b]System.Diagnostics.DebuggerNonUserCodeAttribute[/b] and [b]System.STAThreadAttribute[/b], why?
with 3 Comments