You're comparing apples to oranges. The sizeof operator in C# has no equivalent in VB.NET.
In C#, the sizeof(decimal) is NOT an evaluation of the size of a type. It's a known constant value determined at compile-time, not run-time. In the documentation for sizeof():
The sizeof operator requires an unsafe context. However, the expressions presented in the following table are evaluated in compile time to the corresponding constant values and don't require an unsafe context
At compile time, sizeof(decimal) is simply replaced with the constant value 16. The same would be true for any of the primitive types:
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.maxstack 2
.locals init ([0] int32 l)
IL_0000: nop
IL_0001: ldc.i4.s 16
IL_0003: stloc.0
IL_0004: ldstr "size is {0}"
IL_0009: ldloc.0
IL_000a: box [mscorlib]System.Int32
IL_000f: call string [mscorlib]System.String::Format(string,
object)
IL_0014: call void [mscorlib]System.Console::WriteLine(string)
IL_0019: nop
IL_001a: ret
}
Now, in VB.NET, the documentation for Len() says "Returns an integer containing either the number of characters in a string
or the nominal number of bytes required to store a variable. ... With user-defined types and Object variables, the Len function returns the size as it will be written to the file by the FilePut function..
It's not evaluating the size of the variable in bytes. This is not a bug.
In VB.NET, what you should be doing is
l = Marshal.SizeOf(x), which will return the correct value of 16. But, notice, this time it's not a constant replacement value. It's a function call to an external method that does the evaluation:
.method public static void Main() cil managed
{
.entrypoint
.custom instance void [mscorlib]System.STAThreadAttribute::.ctor() = ( 01 00 00 00 )
.maxstack 2
.locals init ([0] valuetype [mscorlib]System.Decimal x,
[1] int32 l)
IL_0000: nop
IL_0001: ldloc.0
IL_0002: call int32 [mscorlib]System.Runtime.InteropServices.Marshal::SizeOf<valuetype [mscorlib]System.Decimal>(!!0)
IL_0007: stloc.1
IL_0008: ldstr "Length is {0}"
IL_000d: ldloc.1
IL_000e: box [mscorlib]System.Int32
IL_0013: call string [mscorlib]System.String::Format(string,
object)
IL_0018: call void [mscorlib]System.Console::WriteLine(string)
IL_001d: nop
IL_001e: ret
}
If you want the actual number of bytes, evaluated at run-time, in both languages, you would need to call Marshal.SizeOf().