为 VB.NET 和 C# 生成的 IL 差异

发布于 2024-12-01 19:54:11 字数 14084 浏览 2 评论 0原文

今天我在玩实体框架,我读到为 C# 生成的 IL 与 VB.NET 的以下代码不同:

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

C#:

    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());
    }

它们生成以下 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

C#:

    .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

看起来此代码的 VB.NET 版本将在每次执行代码时联系数据库,而 C# 版本将在多次执行代码时从缓存中检索实体。

为什么他们会让两种语言以如此不同的方式表现? 我的误解是,这两种语言只是语法不同,并且生成的 IL 几乎完全相同。

两种语言生成如此不同的 IL 的例子还有吗?

Today I was playing around with Entity Framework and I've read that the generated IL for C# was different than 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

C#:

    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

C#:

    .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

As it seems the VB.NET version of this code will contact the database every time the code is executed while the C# version will retrieve the entities from the cache when the code is executed multiple times.

Why would they make both languages behave in such a different manner?
It was my misconception that both languages just differed in syntax and had almost exactly the same generated IL.

Are there any more examples where both languages generated such different IL?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

耳钉梦 2024-12-08 19:54:11

您看到的部分差异可能是由于调用了结尾的 Select x。由于 VB 查询语法中不需要它,但您显式声明了它,因此 VB 将其包含在编译中。您可以将 VB 语法简单地表述如下:

Dim someCustomer = From x In ctx.Customer 
        Where x.CustomerId.Equals(5) 

由于 C# 在编译时需要本质上无操作的 Select 子句,因此编译器会在生成的 IL 中对其进行优化。

我怀疑在此示例中,如果您使用 CustomerName =(=) "Foo",您会发现 VB 和 C# 生成的表达式树之间存在更大差异,因为 C# 和 VB 对字符串相等性的处理方式非常不同。我见过不少 LINQ 提供程序(包括 LINQ to Bing、LINQ to Twitter、EF Sample Query Provider、NOrm)无法在 VB 中解析 CustomerName = "Foo",因为他们只在 C# 中测试了表达式树解析。

至于您声称 C# 缓存结果,我没有看到针对 Northwind 使用以下代码(使用 LinqPad)。仍然调用数据库3次。

void Main()          
{          
    CallContext();           
    CallContext();           
    CallContext();          
}          

private void CallContext()          
{          
    var someCustomer = from x in Customers          
                       where x.CustomerID.Equals("ALFKI")          
                       select x;          
    Console.WriteLine(someCustomer.Count());          
} 

Part of the differences you are seeing may be due to calling the end Select x. Since it is not required in the VB query syntax but you are explicitly declaring it, VB includes it in the compilation. You could have stated the VB syntax as follows just as easily:

Dim someCustomer = From x In ctx.Customer 
        Where x.CustomerId.Equals(5) 

Since C# requires the essentially no-oped Select clause at compile time, the compiler optimizes it out in the generated IL.

I suspect in this example, you would see greater differences between the generated expression trees between VB and C# if you used CustomerName =(=) "Foo" because C# and VB have very different handling of string equality. I've seen quite a few LINQ providers (including LINQ to Bing, LINQ to Twitter, EF Sample Query Provider, NOrm) that fail to evaute CustomerName = "Foo" in VB because they only tested their expression tree parsing in C#.

As for your claim that C# caches the results, I'm not seeing that using the following code against Northwind (using LinqPad). It is still calling the database 3 times.

void Main()          
{          
    CallContext();           
    CallContext();           
    CallContext();          
}          

private void CallContext()          
{          
    var someCustomer = from x in Customers          
                       where x.CustomerID.Equals("ALFKI")          
                       select x;          
    Console.WriteLine(someCustomer.Count());          
} 
江挽川 2024-12-08 19:54:11

每次调用 CallContext 方法时,这两个代码都会调用数据库。
差异仅在于为 LINQ 表达式生成的表达式树,在本例中差异不大。

正如您在评论中所说,现在您使用了 LINQ 方法链接而不是 LINQ 语法,这就是为什么现在生成的表达式树将是相同的。

Both the code will call the database each time the CallContext method is called.
The difference just in the expression tree generated for the LINQ expression, which in this case is not much of a difference.

As you said in your comment that now you have used LINQ method chaining rather than LINQ syntax, that's why now the generated expression tree will be same.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文