Expression >和Func


 

  以前用EF的時候,由於where的時候有Expression<Func<T>>和Func<T>兩種查詢條件,誤用了Func<T>那個重載,后來還想通過func創建查詢來着,不過失敗了,導致了全表查詢,真是無語.國內的人答的比較言簡意賅(其實我覺得講的不好).還是老外講的明白點.

  翻譯過來吧,就是說Func<T>是方法的委托,而Expression<Func<T>>是拉姆達表達式樹.這個樹狀結構描述了各種各樣惡心的參數(如下圖所示).我們可以用Expression.Compile做成一個委托或者編譯成sql(EF).  

Expression<Func<int>> myExpression = () => 10;

  其實吧, 多用一下你就知道了.Func<T>用的還蠻多的,當時就是用來運行泛化的方法的,而Expression<Func<T>>用在動態查詢拼接的時候比較多,比如 (And和or,拼接多條表達式樹).

 

public static class PredicateBuilder
    {
        public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
        {
            return first.Compose<T>(second, new Func<Expression, Expression, Expression>(Expression.And));
        }

        private static Expression<Func<T, bool>> Compose<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second, Func<Expression, Expression, Expression> merge)
        {
            Expression expression = new ParameterRebinder(second.Parameters[0], first.Parameters[0]).Visit(second.Body);
            return Expression.Lambda<Func<T, bool>>(merge(first.Body, expression), first.Parameters);
        }

        public static Expression<Func<T, bool>> False<T>()
        {
            return item => false;
        }

        public static Expression<Func<T, bool>> Not<T>(this Expression<Func<T, bool>> predicate)
        {
            return Expression.Lambda<Func<T, bool>>(Expression.Not(predicate.Body), predicate.Parameters);
        }

        public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
        {
            return first.Compose<T>(second, new Func<Expression, Expression, Expression>(Expression.Or));
        }

        public static Expression<Func<T, bool>> True<T>()
        {
            return item => true;
        }

        private sealed class ParameterRebinder : ExpressionVisitor
        {
            private readonly ParameterExpression m_From;
            private readonly ParameterExpression m_To;

            public ParameterRebinder(ParameterExpression from, ParameterExpression to)
            {
                this.m_From = from;
                this.m_To = to;
            }

            protected override Expression VisitParameter(ParameterExpression node)
            {
                if (node == this.m_From)
                {
                    node = this.m_To;
                }
                return base.VisitParameter(node);
            }
        }



    }

  

表達式樹惡心的地方,我寫一個orderby給你看看.

        public static IQueryable<TEntity> OrderBy<TEntity>(this IQueryable<TEntity> source, string orderByProperty, bool desc)
        {
            string command = desc ? "OrderByDescending" : "OrderBy";
            var type = typeof(TEntity);//實體的類型
            var property = type.GetProperty(orderByProperty);
            var parameter = Expression.Parameter(type, "o");
            var propertyAccess = Expression.MakeMemberAccess(parameter, property);
            var orderByExpression = Expression.Lambda(propertyAccess, parameter);
            var resultExpression = Expression.Call(typeof(Queryable), command, new Type[] { type, property.PropertyType },
                                          source.Expression, Expression.Quote(orderByExpression));
            return source.Provider.CreateQuery<TEntity>(resultExpression);
        }

  動態linq是需要反射的.而且這種寫法不利於調試.因為你特么完全不知道生成的什么鬼,除非你對這玩意真的很熟.好吧,你贏了.

 

參考鏈接:

Why would you use Expression<Func<T>> rather than Func<T>?

Entity Framework - Func引起的數據庫全表查詢

通過已有Func構造Expression表達式問題


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM