關於Linq中的Lambda表達式中OrderBy的深刻理解

原由:就是一段Linq語句,OrderBy裏面的i是什麼? express

 IQueryable<Student> slist = (from s in EFDB.Student select s).
              OrderBy(i => i.Name).Skip((2 - 1) * 3).Take(3);

說來也奇怪,一樣是形參s就能理解,就是數據集合。 那OrderBy裏面的i是什麼?編程

直接上源碼吧ide

[__DynamicallyInvokable]
public static IOrderedQueryable<TSource> OrderBy<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector)
{
    if (source == null)
    {
        throw Error.ArgumentNull("source");
    }
    if (keySelector == null)
    {
        throw Error.ArgumentNull("keySelector");
    }
    return (IOrderedQueryable<TSource>) source.Provider.CreateQuery<TSource>(Expression.Call(null, ((MethodInfo) MethodBase.GetCurrentMethod()).MakeGenericMethod(new Type[] { typeof(TSource), typeof(TKey) }), new Expression[] { source.Expression, Expression.Quote(keySelector) }));
}

這裏是一個擴展方法,擴展的是 IQueryable<TSource> 類,ui

這個方法關鍵看最後一句話,返回一個CreateQuery方法,看一下它的源碼this

[__DynamicallyInvokable]
IQueryable<TElement> CreateQuery<TElement>(Expression expression);

IL代碼(這個參考,不用在乎)spa

.method public hidebysig newslot abstract virtual instance class System.Linq.IQueryable`1<!!TElement> CreateQuery<TElement>(class System.Linq.Expressions.Expression expression) cil managed
{
    .custom instance void __DynamicallyInvokableAttribute::.ctor()
} 

那麼下面這個就至關於CreateQuery方法的Expression 參數code

Expression.Call(null, ((MethodInfo) MethodBase.GetCurrentMethod()).MakeGenericMethod(new Type[] { typeof(TSource), typeof(TKey) }), new Expression[] { source.Expression, Expression.Quote(keySelector) })

那麼再進一步看看Call方法,這個方法就是返回的Expression 參數blog

[__DynamicallyInvokable]
public static MethodCallExpression Call(Expression instance, MethodInfo method, params Expression[] arguments)
{
    return Call(instance, method, (IEnumerable<Expression>) arguments);
}

再進一步看Callip

[__DynamicallyInvokable]
public static MethodCallExpression Call(Expression instance, MethodInfo method, IEnumerable<Expression> arguments)
{
    ContractUtils.RequiresNotNull(method, "method");
    ReadOnlyCollection<Expression> onlys = arguments.ToReadOnly<Expression>();
    ValidateMethodInfo(method);
    ValidateStaticOrInstanceMethod(instance, method);
    ValidateArgumentTypes(method, ExpressionType.Call, ref onlys);
    if (instance == null)   //如今instance就是等於null
    {
        return new MethodCallExpressionN(method, onlys);
    }
    return new InstanceMethodCallExpressionN(method, instance, onlys);
}

 

繼續看MethodCallExpressionN方法ci

public MethodCallExpressionN(MethodInfo method, IList<Expression> args) : base(method)
{
    this._arguments = args;
}

看到這裏,咱們就能夠反推回去,Call方法最後就是把arguments(IEnumerable<Expression>集合)返回給CreateQuery,而這個arguments形參就是CreateQuery的

new Expression[] { source.Expression, Expression.Quote(keySelector) }

再看看這裏的Quote方法

[__DynamicallyInvokable]
public static UnaryExpression Quote(Expression expression)
{
    RequiresCanRead(expression, "expression");
    if (!(expression is LambdaExpression))  //若是不是lambda表達式,則拋異常
    {
        throw Error.QuotedExpressionMustBeLambda();
    }
    return new UnaryExpression(ExpressionType.Quote, expression, expression.GetType(), null); //
}

看到這裏,終於知道原來

public static IOrderedQueryable<TSource> OrderBy<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector)

能夠理解爲

public static IOrderedQueryable<TSource> OrderBy(LambdaExpression )

至此,終於明白開頭這句話的

 (from s in EFDB.Student select s)
.OrderBy(i
=> i.Name)
.Skip((2 - 1) * 3)
.Take(3);

OrderBy裏面的i是取決於以前是誰調用的這個方法

 

上面source表明實體集,source.Expression表明實體集中的每個實體。=> 也就是說lambda表達式中的形參i,表明一個實體,而不是實體集。

我的推測,Linq中OrderBy、Where都是返回的按照各自method、篩選器以後的集合,泛型委託。這種寫法有點像鏈式編程。

 

完畢!

若有不正確的地方,請不吝賜教。

感謝個人幾位好友:時同窗、邵同窗、倪同窗、黃同窗等對我一直以來的幫助。

由於咱們都知道一個道理:單則易折、衆則難摧。

相關文章
相關標籤/搜索