Linq相關:
- 10-10-02LINQ如何返回業務實體到上層邏輯
- 10-07-25LINQ中怎么使用LIKE方法?
- 10-03-19
- 10-03-19linq如何去除重復結果?
- 10-03-12Linq中的not in 語句應該怎么寫?
Linq是以下列方式編譯:
首先,LINQ 查詢表達式轉換為方法調用:
public static void Main() { var query = db.Cars.Select<Car, Car>(c => c); foreach (Car aCar in query) { Console.WriteLine(aCar.Name); } }
如果
db.Cars
的類型是IEnumerable<Car>
(即它的 LINQ,對象),然后 lambda 表達式變成了一個單獨的方法:private Car lambda0(Car c) { return c; } private Func<Car, Car> CachedAnonymousMethodDelegate1; public static void Main() { if (CachedAnonymousMethodDelegate1 == null) CachedAnonymousMethodDelegate1 = new Func<Car, Car>(lambda0); var query = db.Cars.Select<Car, Car>(CachedAnonymousMethodDelegate1); foreach // ... }
在現實中不調用該方法
lambda0
但東西喜歡<Main>b__0
(在Main
是包含方法的名稱)。同樣,緩存的委托實際上調用CS$<>9__CachedAnonymousMethodDelegate1
。如果您正在使用 SQL LINQ 然后
db.Cars
類型將為IQueryable<Car>
,此步驟是非常不同。相反,它會到表達式目錄樹的 lambda 表達式:public static void Main() { var parameter = Expression.Parameter(typeof(Car), "c"); var lambda = Expression.Lambda<Func<Car, Car>>(parameter, new ParameterExpression[] { parameter })); var query = db.Cars.Select<Car, Car>(lambda); foreach // ... }
在
foreach
循環變成一個try/finally
塊 (這是相同的兩個):IEnumerator<Car> enumerator = null; try { enumerator = query.GetEnumerator(); Car aCar; while (enumerator.MoveNext()) { aCar = enumerator.Current; Console.WriteLine(aCar.Name); } } finally { if (enumerator != null) ((IDisposable)enumerator).Dispose(); }
最后,這是為 IL 編譯預期的方式。以下是為
IEnumerable<Car>
:// Put db.Cars on the stack L_0016: ldloc.0 L_0017: callvirt instance !0 DatabaseContext::get_Cars() // “if” starts here L_001c: ldsfld Func<Car, Car> Program::CachedAnonymousMethodDelegate1 L_0021: brtrue.s L_0034 L_0023: ldnull L_0024: ldftn Car Program::lambda0(Car) L_002a: newobj instance void Func<Car, Car>::.ctor(object, native int) L_002f: stsfld Func<Car, Car> Program::CachedAnonymousMethodDelegate1 // Put the delegate for “c => c” on the stack L_0034: ldsfld Func<Car, Car> Program::CachedAnonymousMethodDelegate1 // Call to Enumerable.Select() L_0039: call IEnumerable<!!1> Enumerable::Select<Car, Car>(IEnumerable<!!0>, Func<!!0, !!1>) L_003e: stloc.1 // “try” block starts here L_003f: ldloc.1 L_0040: callvirt instance IEnumerator<!0> IEnumerable<Car>::GetEnumerator() L_0045: stloc.3 // “while” inside try block starts here L_0046: br.s L_005a L_0048: ldloc.3 // body of while starts here L_0049: callvirt instance !0 IEnumerator<Car>::get_Current() L_004e: stloc.2 L_004f: ldloc.2 L_0050: ldfld string Car::Name L_0055: call void Console::WriteLine(string) L_005a: ldloc.3 // while condition starts here L_005b: callvirt instance bool IEnumerator::MoveNext() L_0060: brtrue.s L_0048 // end of while L_0062: leave.s L_006e // end of try // “finally” block starts here L_0064: ldloc.3 L_0065: brfalse.s L_006d L_0067: ldloc.3 L_0068: callvirt instance void IDisposable::Dispose() L_006d: endfinally
已編譯的代碼,
IQueryable<Car>
版本是按預期也。這里是重要的部分,有別于上述 (本地變量會有不同的偏移和名稱現在,但讓我們忽略的):// typeof(Car) L_0021: ldtoken Car L_0026: call Type Type::GetTypeFromHandle(RuntimeTypeHandle) // Expression.Parameter(typeof(Car), "c") L_002b: ldstr "c" L_0030: call ParameterExpression Expression::Parameter(Type, string) L_0035: stloc.3 // Expression.Lambda(...) L_0036: ldloc.3 L_0037: ldc.i4.1 // var paramArray = new ParameterExpression[1] L_0038: newarr ParameterExpression L_003d: stloc.s paramArray L_003f: ldloc.s paramArray L_0041: ldc.i4.0 // paramArray[0] = parameter; L_0042: ldloc.3 L_0043: stelem.ref L_0044: ldloc.s paramArray L_0046: call Expression<!!0> Expression::Lambda<Func<Car, Car>>(Expression, ParameterExpression[]) // var query = Queryable.Select(...); L_004b: call IQueryable<!!1> Queryable::Select<Car, Car>(IQueryable<!!0>, Expression<Func<!!0, !!1>>) L_0050: stloc.1