表达式树 学习笔记

参考 :

http://www.cnblogs.com/jesse2013/p/expressiontree-part1.html

https://blog.csdn.net/WuLex/article/details/80766862 表达式树, 委托,匿名函数,lambda 表达式, Action, Func 的关系

讲讲 上面这些的关系

委托是古老的, 后来有了泛型就用 Action 和 Func 

然后开始玩匿名就有了 lambda 表达式.

lambda 基本上可以等价于委托和匿名函数. 

表达式树的用途是表达逻辑,然后存起来传来传去,解析,修改等等. 

它的其中一个用途是可以用来做 lambda 表达式,然后就可以创建出委托, Action Func 

当然它还有更广的用途啦. 

所以如果我们想同台创建一个匿名函数,就可以创建表达式树,然后 Expression.Lambda( delegateType, expression ... ).Complie() 这样来使用啦

 

 

里面有教

Expression.Loop
Expression.Call
Expression.Constant
Expression.Block
Expression.Lambda
Expression.Parameter
Expression.Assign =
Expression.AddAssign
Expression.DivideAssign
Expression.Label
Expression.IfThenElse
Expression.LessThanOrEqual
Expression.PostIncrementAssign ++
Expression.Break
Expression.TypeIs ("spruce" Is Int32)
Expression.ArrayAccess array[0]
Expression.New

 

如果你认真想学习的话,请去上面这个链接。

 

public object getProps<T>(DbSet<T> query, int id, string navigationPropName) where T : class
{
    //我们想 return db.?.Where(c => c.id == ?).SelectMany(c => c.?);
    //或者想 return db.?.Include(c => c.?).FirstOrDefaultAsync(c => c.id == ?).Result.?
    //? 表示了动态的值
        
    //note : include 使用 Expression.Call 会error, 用 Invoke 就不会, 不清楚为什么
    //note : 反射选择方法时,是直接选取第几个,一但 dll 版本换了, 可能就会被影响了 (以后如果想彻底解决的话 : http://stackoverflow.com/questions/3631547/select-right-generic-method-with-reflection)

    Type entityType = typeof(T); //e.g. Color
    Type navigationPropType = entityType.GetProperty(navigationPropName).PropertyType; //e.g. List<Size>
    if (navigationPropType.IsGenericType) //is List 的情况
    {
        //添加 where 
        //e.g. db.colors.where(c => c.id == id);
        //e.g. Expression<Func<Color, bool>> exp = c => c.id == 1;
        //e.g. var query = Queryable.Where<Color>(db.colors, exp);  

        Type delegateType = typeof(Func<,>).MakeGenericType(entityType, typeof(bool));

        //e.g. c => c.id == 1
        ParameterExpression parameter = Expression.Parameter(entityType, "c");
        ConstantExpression idValue = Expression.Constant(id, typeof(int));
        Expression idProp = Expression.Property(parameter, "id");
        BinaryExpression body = Expression.Equal(idProp, idValue);
        //需要组合2次哦
        LambdaExpression lambda = Expression.Lambda(body, new[] { parameter });           
        lambda = Expression.Lambda(delegateType, lambda.Body, lambda.Parameters);
           
        IQueryable source = (IQueryable)(query);
        var queryAfterWhere = source.Provider.CreateQuery(Expression.Call(
                    typeof(Queryable), "Where",  //Queryable.Where
                    new Type[] { entityType }, //e.g. <Color>
                    source.Expression, Expression.Quote(lambda))); //e.g. (db.colors, exp)
            

        //添加 selectMany 
        //e.g. db.colors.where(c => c.id == id).selectMany(c => c.sizes);
        //e.g. Expression<Func<Color, IEnumerable<Size>>> exp = c => c.sizes;
        //e.g. var query = Queryable.SelectMany<Color,Size>(db.colors, exp);  

        Type navigationPropSingleType = navigationPropType.GetGenericArguments()[0]; //e.g. Size

        Type enumerableType = typeof(IEnumerable<>).MakeGenericType(navigationPropSingleType); //e.g. IEnumerable<Size>
        delegateType = typeof(Func<,>).MakeGenericType(entityType, enumerableType); //e.g. Func<Color, IEnumerable<Size>>

        //e.g. c => c.sizes
        parameter = Expression.Parameter(entityType, "c");
        Expression navigationProp = Expression.Property(parameter, navigationPropName);
        lambda = Expression.Lambda(navigationProp, new[] { parameter });

        //e.g. Expression<Func<Color, IEnumerable<Size>>> exp = c => c.sizes
        lambda = Expression.Lambda(delegateType, lambda.Body, lambda.Parameters);

        source = (IQueryable)(queryAfterWhere);

        var queryAfterSelectMany = source.Provider.CreateQuery(Expression.Call(
                    typeof(Queryable), "SelectMany",  //Queryable.SelectMany
                    new Type[] { entityType, navigationPropSingleType }, //e.g. <Color, Size>
                    source.Expression, Expression.Quote(lambda))); //e.g. (db.colors, exp)

        return queryAfterSelectMany;
    }
    else
    {
        //这里和上面不同之处就是使用了反射Invoke来调用方法,而上面是使用Expression.Call 
        //这里用 Expression.Call 会error, 没搞懂为什么啦
        Type delegateType = typeof(Func<,>).MakeGenericType(entityType, navigationPropType);
        var parameter = Expression.Parameter(entityType, "c");
        Expression navigationProp = Expression.Property(parameter, navigationPropName);
        var lambda = Expression.Lambda(navigationProp, new[] { parameter });
        lambda = Expression.Lambda(delegateType, lambda.Body, lambda.Parameters);
        var methods = typeof(QueryableExtensions).GetMethods().Where(m => m.Name == "Include").ToList();
        var method = methods[2].MakeGenericMethod(typeof(Color), typeof(Product));
        var queryAfterInclude = (IQueryable)method.Invoke(null, new object[] { query, lambda });
            
        delegateType = typeof(Func<,>).MakeGenericType(entityType, typeof(bool));
        ConstantExpression idValue = Expression.Constant(1, typeof(int));
        Expression idProp = Expression.Property(parameter, "id");
        BinaryExpression body = Expression.Equal(idProp, idValue);
        lambda = Expression.Lambda(body, new[] { parameter });
        lambda = Expression.Lambda(delegateType, lambda.Body, lambda.Parameters);
        methods = typeof(QueryableExtensions).GetMethods().Where(m => m.Name == "FirstOrDefaultAsync").ToList();
        method = methods[2].MakeGenericMethod(entityType);
        var result = method.Invoke(null, new object[] { queryAfterInclude, lambda });

        var list = result.GetType().GetProperty("Result").GetValue(result, null);
        var navigationResource = list.GetType().GetProperty(navigationPropName).GetValue(list, null);
        return navigationResource;
    }
}

 

posted @ 2015-09-19 12:39  兴杰  阅读(283)  评论(0编辑  收藏  举报