1. 程式人生 > >Lambda表達式樹解析(下)

Lambda表達式樹解析(下)

equal arguments provider inf gets 轉換 lis bin text

概述

  前面章節,總結了Lambda樹的構建,那麽怎麽解析Lambda表達式樹那?Lambda表達式是一種委托構造而成,如果能夠清晰的解析Lambda表達式樹,那麽就能夠理解Lambda表達式要傳遞的正式意圖。解析Lambda表達式樹意義很大,比如我們用的EF框架、Rafy框架,裏面封裝了大量的Lambda查詢表達式,通過解析表達式轉換成SQL語句,即可以查詢數據庫,將數據呈現給前臺用戶;

Lambda表達式樹解析

  下面代碼塊是標識Express各個節點的信息,ExpressionType.Call標識表達式中含有方法調用,常用到該類型的3個參數為:Method.DeclaringType和Argument和object。ExpressionType.Quote標識表達式中含有一元表達式,常用到的參數是Operand,裏面放置了Lamble具體表達式。

public string AnalysisExpression(Expression exp)
        {
            string TextSql = "";
            switch (exp.NodeType)
            {
                case ExpressionType.Call:
                    {
                        MethodCallExpression mce = exp as MethodCallExpression;
                        Console.WriteLine(
"The Method Is {0}", mce.Method.Name); Console.WriteLine("The Method TypeOf {0}", mce.Method.DeclaringType); if (mce.Method.DeclaringType == typeof(string)) { break; }
if (mce.Method.DeclaringType != typeof(Queryable)){ break; } for (int i = 0; i < mce.Arguments.Count; i++) { TextSql+=AnalysisExpression(mce.Arguments[i]); } } break; case ExpressionType.Quote: { UnaryExpression ue = exp as UnaryExpression; TextSql += AnalysisExpression(ue.Operand); } break; case ExpressionType.Lambda: { LambdaExpression le = exp as LambdaExpression; AnalysisExpression(le.Body); TextSql+= ExpressTreeAnalysis.GetSqlByExpression(le.Body); } break; case ExpressionType.AndAlso: case ExpressionType.OrElse: case ExpressionType.Equal: { BinaryExpression be = exp as BinaryExpression; Console.WriteLine("The Method Is {0}", exp.NodeType.ToString()); TextSql += AnalysisExpression(be.Left); TextSql += AnalysisExpression(be.Right); } break; case ExpressionType.Constant: { ConstantExpression ce = exp as ConstantExpression; Console.WriteLine("The Value Type Is {0}", ce.Value.ToString()); } break; case ExpressionType.Parameter: { ParameterExpression pe = exp as ParameterExpression; Console.WriteLine("The Parameter Is {0}", pe.Name); } break; default: { Console.Write("UnKnow"); } break; } return TextSql; }

由於自定義集合實現IQueryable和IQueryProvider來自定義查詢項

實現IQuable定義的類:

public class BlogQueryable<T> : IQueryable<T>
    {
        BlogQueryProvider provider;
        Expression expression;

        public BlogQueryable(BlogQueryProvider provider)
        {
            if (provider == null)
            {
                throw new ArgumentNullException("provider");
            }
            this.provider = provider;
            this.expression = Expression.Constant(this);
        }

        public BlogQueryable(BlogQueryProvider provider, Expression expression)
        {
            this.provider = provider;
            this.expression = expression;
        }
        public Type ElementType
        {
            get
            {
                return typeof(T);
            }
        }

        public Expression Expression
        {
            get
            {
                return expression;
            }
        }

        public IQueryProvider Provider
        {
            get
            {
                return provider;
            }
        }

        public IEnumerator<T> GetEnumerator()
        {
            return ((IEnumerable<T>)this.provider.Execute(this.expression)).GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return ((IEnumerable)this.provider.Execute(this.expression)).GetEnumerator();
        }


        public void Where2(Expression<Func<T, bool>> func)
        {
            string TextSql = ExpressTreeAnalysis.GetSqlByExpression(func.Body);
        }
    }

實現IQueryProvider接口的類,CreateQuery解析表達式樹而Execute則是執行解析後的SQL語句,查詢數據,填充list集合:

public class BlogQueryProvider : IQueryProvider
{
public IQueryable CreateQuery(Expression expression) { Type elementType = expression.Type; try { return (IQueryable)Activator.CreateInstance(typeof(BlogQueryable<>).MakeGenericType(elementType), new object[] { this, expression }); } catch(TargetInvocationException tie) { throw tie.InnerException; } } public IQueryable<TElement> CreateQuery<TElement>(Expression expression) { //string TextSql= ExpressTreeAnalysis.GetSqlByExpression(((Expression)(expression as MethodCallExpression).Arguments[1]).bo); //Console.WriteLine(TextSql); AnalysisExpression(expression); return new BlogQueryable<TElement>(this, expression); } public object Execute(Expression expression) { return this.Execute2<object>(expression); } public TResult Execute<TResult>(Expression expression) { return (TResult)this.Execute2<TResult>(expression); } public TResult Execute2<TResult>(Expression expression) { return (TResult)Activator.CreateInstance(typeof(TResult)); } }

具體下面即可使用查詢

        public void MyTestMethod()
        {
            Catagory cag = new Catagory("四大名著點評");

            IList<Blog> Blogs = new List<Blog>();
            Blog bok = new Blog() { Title = "紅樓夢", Conent = "紅樓夢書籍不錯",
         User = new Author() { UserName = "曹雪芹", BirefInfor = "中國清代著名作家" } }; bok.Catagories.Add(cag); bok.Catagories.Add(new Catagory("紅樓夢專欄")); Blogs.Add(bok); Blog bok2 = new Blog() { Title = "三國演義", Conent = "三國鼎立時期的描述",
        User = new Author() { UserName = "羅貫中", BirefInfor = "中國元末明初著名作家" } }; bok2.Catagories.Add(cag); bok2.Catagories.Add(new Catagory("三國演義專欄")); Blogs.Add(bok2); Blog bok3 = new Blog() { Title = "西遊記", Conent = "西遊記講述四個徒弟和一個師傅取經事情",
User = new Author() { UserName = "吳承恩", BirefInfor = "中國明代傑出的小說家" } }; bok2.Catagories.Add(cag); bok2.Catagories.Add(new Catagory("西遊記專欄")); Blogs.Add(bok3); Blog bok4 = new Blog() { Title = "水滸傳", Conent = "描述梁山好漢劫富濟貧的故事",
          User = new Author() { UserName = "施耐庵", BirefInfor = "中國明代傑出的小說家" } }; bok2.Catagories.Add(cag); bok2.Catagories.Add(new Catagory("水滸傳專欄")); Blogs.Add(bok4); BlogQueryProvider Provider = new BlogQueryProvider(); BlogQueryable<Blog> Quble = new BlogQueryable<Blog>(Provider); var t2 = Quble.Where(p => p.Title == "123" && p.Conent.Contains("水滸")); }

參考代碼下載

後續:針對解析Lambda表達式樹成SQL,本人也是剛剛入門,至於完全要解析成SQL,還需要研究......

Lambda表達式樹解析(下)