Today I played with the Entity Framework, and I read that the generated IL for C # was different from VB.NET for the following code:
VB.NET:
Dim ctx As New TravelEntities Sub Main() CallContext() CallContext() CallContext() End Sub Private Sub CallContext() Dim someCustomer = From x In ctx.Customer Where x.CustomerId.Equals(5) Select x Console.WriteLine(someCustomer.Count()) End Sub
FROM#:
private static TravelEntities ctx = new TravelEntities(); static void Main(string[] args) { CallContext(); CallContext(); CallContext(); } private static void CallContext() { var someCustomer = from x in ctx.Customer where x.CustomerId.Equals(5) select x; Console.WriteLine(someCustomer.Count()); }
They produce the following IL:
VB:
.method private static void CallContext() cil managed { // Code size 195 (0xc3) .maxstack 7 .locals init ([0] class [System.Core]System.Linq.IQueryable`1<class VB_IL_Difference.Customer> someCustomer, [1] class [System.Core]System.Linq.Expressions.ParameterExpression VB$t_ref$S0, [2] class [System.Core]System.Linq.Expressions.Expression[] VB$t_array$S0, [3] class [System.Core]System.Linq.Expressions.ParameterExpression[] VB$t_array$S1, [4] class [System.Core]System.Linq.Expressions.ParameterExpression VB$t_ref$S1, [5] class [System.Core]System.Linq.Expressions.ParameterExpression[] VB$t_array$S2) IL_0000: nop IL_0001: ldsfld class VB_IL_Difference.TravelEntities VB_IL_Difference.Module1::ctx IL_0006: callvirt instance class [System.Data.Entity]System.Data.Objects.ObjectSet`1<class VB_IL_Difference.Customer> VB_IL_Difference.TravelEntities::get_Customer() IL_000b: ldtoken VB_IL_Difference.Customer IL_0010: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) IL_0015: ldstr "x" IL_001a: call class [System.Core]System.Linq.Expressions.ParameterExpression [System.Core]System.Linq.Expressions.Expression::Parameter(class [mscorlib]System.Type, string) IL_001f: stloc.1 IL_0020: ldloc.1 IL_0021: ldtoken method instance int32 VB_IL_Difference.Customer::get_CustomerId() IL_0026: call class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Reflection.MethodBase::GetMethodFromHandle(valuetype [mscorlib]System.RuntimeMethodHandle) IL_002b: castclass [mscorlib]System.Reflection.MethodInfo IL_0030: call class [System.Core]System.Linq.Expressions.MemberExpression [System.Core]System.Linq.Expressions.Expression::Property(class [System.Core]System.Linq.Expressions.Expression, class [mscorlib]System.Reflection.MethodInfo) IL_0035: ldtoken method instance bool [mscorlib]System.Int32::Equals(int32) IL_003a: call class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Reflection.MethodBase::GetMethodFromHandle(valuetype [mscorlib]System.RuntimeMethodHandle) IL_003f: castclass [mscorlib]System.Reflection.MethodInfo IL_0044: ldc.i4.1 IL_0045: newarr [System.Core]System.Linq.Expressions.Expression IL_004a: stloc.2 IL_004b: ldloc.2 IL_004c: ldc.i4.0 IL_004d: ldc.i4.5 IL_004e: box [mscorlib]System.Int32 IL_0053: ldtoken [mscorlib]System.Int32 IL_0058: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) IL_005d: call class [System.Core]System.Linq.Expressions.ConstantExpression [System.Core]System.Linq.Expressions.Expression::Constant(object, class [mscorlib]System.Type) IL_0062: stelem.ref IL_0063: nop IL_0064: ldloc.2 IL_0065: call class [System.Core]System.Linq.Expressions.MethodCallExpression [System.Core]System.Linq.Expressions.Expression::Call(class [System.Core]System.Linq.Expressions.Expression, class [mscorlib]System.Reflection.MethodInfo, class [System.Core]System.Linq.Expressions.Expression[]) IL_006a: ldc.i4.1 IL_006b: newarr [System.Core]System.Linq.Expressions.ParameterExpression IL_0070: stloc.3 IL_0071: ldloc.3 IL_0072: ldc.i4.0 IL_0073: ldloc.1 IL_0074: stelem.ref IL_0075: nop IL_0076: ldloc.3 IL_0077: call class [System.Core]System.Linq.Expressions.Expression`1<!!0> [System.Core]System.Linq.Expressions.Expression::Lambda<class [mscorlib]System.Func`2<class VB_IL_Difference.Customer,bool>>(class [System.Core]System.Linq.Expressions.Expression, class [System.Core]System.Linq.Expressions.ParameterExpression[]) IL_007c: call class [System.Core]System.Linq.IQueryable`1<!!0> [System.Core]System.Linq.Queryable::Where<class VB_IL_Difference.Customer>(class [System.Core]System.Linq.IQueryable`1<!!0>, class [System.Core]System.Linq.Expressions.Expression`1<class [mscorlib]System.Func`2<!!0,bool>>) IL_0081: ldtoken VB_IL_Difference.Customer IL_0086: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) IL_008b: ldstr "x" IL_0090: call class [System.Core]System.Linq.Expressions.ParameterExpression [System.Core]System.Linq.Expressions.Expression::Parameter(class [mscorlib]System.Type, string) IL_0095: stloc.s VB$t_ref$S1 IL_0097: ldloc.s VB$t_ref$S1 IL_0099: ldc.i4.1 IL_009a: newarr [System.Core]System.Linq.Expressions.ParameterExpression IL_009f: stloc.s VB$t_array$S2 IL_00a1: ldloc.s VB$t_array$S2 IL_00a3: ldc.i4.0 IL_00a4: ldloc.s VB$t_ref$S1 IL_00a6: stelem.ref IL_00a7: nop IL_00a8: ldloc.s VB$t_array$S2 IL_00aa: call class [System.Core]System.Linq.Expressions.Expression`1<!!0> [System.Core]System.Linq.Expressions.Expression::Lambda<class [mscorlib]System.Func`2<class VB_IL_Difference.Customer,class VB_IL_Difference.Customer>>(class [System.Core]System.Linq.Expressions.Expression, class [System.Core]System.Linq.Expressions.ParameterExpression[]) IL_00af: call class [System.Core]System.Linq.IQueryable`1<!!1> [System.Core]System.Linq.Queryable::Select<class VB_IL_Difference.Customer,class VB_IL_Difference.Customer>(class [System.Core]System.Linq.IQueryable`1<!!0>, class [System.Core]System.Linq.Expressions.Expression`1<class [mscorlib]System.Func`2<!!0,!!1>>) IL_00b4: stloc.0 IL_00b5: ldloc.0 IL_00b6: call int32 [System.Core]System.Linq.Queryable::Count<class VB_IL_Difference.Customer>(class [System.Core]System.Linq.IQueryable`1<!!0>) IL_00bb: call void [mscorlib]System.Console::WriteLine(int32) IL_00c0: nop IL_00c1: nop IL_00c2: ret } // end of method Module1::CallContext
FROM#:
.method private hidebysig static void CallContext() cil managed { // Code size 141 (0x8d) .maxstack 7 .locals init ([0] class [System.Core]System.Linq.IQueryable`1<class C_IL_Difference.Customer> someCustomer, [1] class [System.Core]System.Linq.Expressions.ParameterExpression CS$0$0000, [2] class [System.Core]System.Linq.Expressions.Expression[] CS$0$0001, [3] class [System.Core]System.Linq.Expressions.ParameterExpression[] CS$0$0002) IL_0000: nop IL_0001: ldsfld class C_IL_Difference.TravelEntities C_IL_Difference.Program::ctx IL_0006: callvirt instance class [System.Data.Entity]System.Data.Objects.ObjectSet`1<class C_IL_Difference.Customer> C_IL_Difference.TravelEntities::get_Customer() IL_000b: ldtoken C_IL_Difference.Customer IL_0010: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) IL_0015: ldstr "x" IL_001a: call class [System.Core]System.Linq.Expressions.ParameterExpression [System.Core]System.Linq.Expressions.Expression::Parameter(class [mscorlib]System.Type, string) IL_001f: stloc.1 IL_0020: ldloc.1 IL_0021: ldtoken method instance int32 C_IL_Difference.Customer::get_CustomerId() IL_0026: call class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Reflection.MethodBase::GetMethodFromHandle(valuetype [mscorlib]System.RuntimeMethodHandle) IL_002b: castclass [mscorlib]System.Reflection.MethodInfo IL_0030: call class [System.Core]System.Linq.Expressions.MemberExpression [System.Core]System.Linq.Expressions.Expression::Property(class [System.Core]System.Linq.Expressions.Expression, class [mscorlib]System.Reflection.MethodInfo) IL_0035: ldtoken method instance bool [mscorlib]System.Int32::Equals(int32) IL_003a: call class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Reflection.MethodBase::GetMethodFromHandle(valuetype [mscorlib]System.RuntimeMethodHandle) IL_003f: castclass [mscorlib]System.Reflection.MethodInfo IL_0044: ldc.i4.1 IL_0045: newarr [System.Core]System.Linq.Expressions.Expression IL_004a: stloc.2 IL_004b: ldloc.2 IL_004c: ldc.i4.0 IL_004d: ldc.i4.5 IL_004e: box [mscorlib]System.Int32 IL_0053: ldtoken [mscorlib]System.Int32 IL_0058: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) IL_005d: call class [System.Core]System.Linq.Expressions.ConstantExpression [System.Core]System.Linq.Expressions.Expression::Constant(object, class [mscorlib]System.Type) IL_0062: stelem.ref IL_0063: ldloc.2 IL_0064: call class [System.Core]System.Linq.Expressions.MethodCallExpression [System.Core]System.Linq.Expressions.Expression::Call(class [System.Core]System.Linq.Expressions.Expression, class [mscorlib]System.Reflection.MethodInfo, class [System.Core]System.Linq.Expressions.Expression[]) IL_0069: ldc.i4.1 IL_006a: newarr [System.Core]System.Linq.Expressions.ParameterExpression IL_006f: stloc.3 IL_0070: ldloc.3 IL_0071: ldc.i4.0 IL_0072: ldloc.1 IL_0073: stelem.ref IL_0074: ldloc.3 IL_0075: call class [System.Core]System.Linq.Expressions.Expression`1<!!0> [System.Core]System.Linq.Expressions.Expression::Lambda<class [mscorlib]System.Func`2<class C_IL_Difference.Customer,bool>>(class [System.Core]System.Linq.Expressions.Expression, class [System.Core]System.Linq.Expressions.ParameterExpression[]) IL_007a: call class [System.Core]System.Linq.IQueryable`1<!!0> [System.Core]System.Linq.Queryable::Where<class C_IL_Difference.Customer>(class [System.Core]System.Linq.IQueryable`1<!!0>, class [System.Core]System.Linq.Expressions.Expression`1<class [mscorlib]System.Func`2<!!0,bool>>) IL_007f: stloc.0 IL_0080: ldloc.0 IL_0081: call int32 [System.Core]System.Linq.Queryable::Count<class C_IL_Difference.Customer>(class [System.Core]System.Linq.IQueryable`1<!!0>) IL_0086: call void [mscorlib]System.Console::WriteLine(int32) IL_008b: nop IL_008c: ret } // end of method Program::CallContext
It appears that the version of this VB.NET code will contact the database every time the code is executed, and the C # version will retrieve objects from the cache when the code is executed several times.
Why do they make both languages ​​behave differently? It was my fallacy that both languages ​​simply differed in syntax and had almost exactly the same generated IL.
Are there any other examples where both languages ​​generate such different ILs?