expression expression tree (a)

  expression tree expression tree is a new feature introduced in .NET 3.5, simply a syntax tree, or a kind of data structure (Expression). The expression tree is arguably one of the core Linq, Linq Why is one of the core of it? Because the expression tree that is no longer only able c # compiled into IL, we can generate an expression tree by c #, as a result of the intermediate format, converts it into native language of the target platform. Such as SQL. We used Linq to sql is this generates SQL statements.

      In the expression .net frame redefined

the using the System.Collections.Generic;
 the using the System.Runtime.CompilerServices; 

namespace System.Linq.Expressions 
{ 
    // 
    // Summary:
     //      the strongly typed Lambda expression represents an expression form of a tree data structure. This class can not be inherited.
    // 
    // type parameter:
     //    TDelegate:
     //      type of the delegate, System.Linq.Expressions.Expression`1 representation. 
    public  Sealed  class the Expression <TDelegate> : LambdaExpression 
    { 
        // 
        // Summary:
         //      compiler is described by the expression tree lambda expression executable code, and generates a delegate that represents the lambda expression.
        // 
        // Returns:
        //      compiled lambda expression System.Linq.Expressions.Expression`1 type of delegate representation TDelegate described. 
        public TDelegate the Compile ();
         // 
        // Summary:
         //      will generate a delegate that represents the lambda expression.
        // 
        // Parameters:
         //    debugInfoGenerator:
         //      by the compiler for the tag sequence and add debug point information generator annotated local variables.
        // 
        // Returns:
         //      a delegate compiled version of lambda included. 
        public TDelegate the Compile (DebugInfoGenerator debugInfoGenerator);
         // 
        // Summary:
         //      create a new expression that is similar to this expression, but using the supplied children. If all children are the same, it will return this expression.
        //
        // Parameters:
         //    body:
         //      System.Linq.Expressions.LambdaExpression.Body result attribute.
        // 
        //    the Parameters:
         //      System.Linq.Expressions.LambdaExpression.Parameters result attribute.
        // 
        // Returns:
         //      If the child does not change, then the expression for this purpose; otherwise, has children expressions have been updated. 
        public the Expression <TDelegate> the Update (the Expression body, the IEnumerable <ParameterExpression> Parameters);
         protected  Internal  the override the Expression the Accept (ExpressionVisitor hit); 
    } 
}
View Code

  It can be seen, Expression <TDelegate> seal is essentially a generic class, we can get an expression tree by providing Expression <TDelegate> assigning a class lambel expression way.

  We further analyze, Expression <TDelegate> generic class inherits from LambdaExpression, it is an abstract class,

a using System.Collections.ObjectModel;
 a using System.Diagnostics;
 a using System.Reflection.Emit;
 a using System.Runtime.CompilerServices; 

namespace System.Linq.Expressions 
{ 
    // 
    // Summary:
     //      introduces lambda expressions. It captures a method similar to the .NET code block body. 
    [DebuggerTypeProxy ( typeof (LambdaExpressionProxy))]
     public  abstract  class LambdaExpression: Expression 
    { 
        // 
        // Summary:
         //      Gets the static type of this System.Linq.Expressions.Expression indicated expression.
        // 
        // Returns:
        //      represents the static type of expression of System.Linq.Expressions.LambdaExpression.Type. 
        public  Sealed  the override the Type the Type { GET ;}
         // 
        // Summary:
         //      Returns this node type System.Linq.Expressions.Expression.
        // 
        // Returns:
         //      used to represent System.Linq.Expressions.ExpressionType this expression. 
        public  Sealed  the override ExpressionType the NodeType { GET ;}
         // 
        // Summary:
         //      acquisition parameters of the lambda expression.
        // 
        // Returns:
         //     A System.Collections.ObjectModel.ReadOnlyCollection`1 of System.Linq.Expressions.ParameterExpression
         //      object representing the parameters of the lambda expression. 
        public the ReadOnlyCollection <ParameterExpression> the Parameters { GET ;}
         // 
        // Summary:
         //      Get the name of the lambda expression.
        // 
        // Returns:
         //      name Lambda expressions. 
        public  String the Name { GET ;}
         // 
        // Summary:
         //      Get the body of the lambda expression.
        // 
        // Returns:
         //     System.Linq.Expressions.Expression represents the body of the lambda expression. 
        public the Expression Body { GET ;}
         // 
        // Summary:
         //      Get the return type of the lambda expression.
        // 
        // return the result:
         //      System.Type object representing the type of the lambda expression. 
        public the Type ReturnType { GET ;}
         // 
        // Summary:
         //      Gets a value indicating whether to use tail call optimizing compiler lambda expression.
        // 
        // Returns:
         //      if the lambda expression will be compiled with the tail call optimization, otherwise it is false, then true. 
        public  BOOL tailcall { GET ;}

        // 
        // Summary:
         //      will generate a delegate that represents the lambda expression.
        // 
        // Returns:
         //      a System.Delegate, which contains a compiled version of the lambda expression. 
        public Delegate the Compile ();
         // 
        // Summary:
         //      will generate a delegate that represents the lambda expression.
        // 
        // Parameters:
         //    debugInfoGenerator:
         //      by the compiler for the tag sequence and add debug point information generator annotated local variables.
        // 
        // Returns:
         //      a delegate compiled version of lambda included. 
        public the Delegate the Compile (DebugInfoGenerator debugInfoGenerator);
         //
        // Summary:
         //      the Lambda will compile the method definition.
        // 
        // Parameters:
         //    Method,:
         //      a System.Reflection.Emit.MethodBuilder This will be used to save a lambda IL. 
        public  void CompileToMethod (MethodBuilder Method,);
         // 
        // Summary:
         //      The method definition and custom debug information compiled lambda.
        // 
        // Parameters:
         //    Method,:
         //      a System.Reflection.Emit.MethodBuilder This will be used to save a lambda IL.
        // 
        //    debugInfoGenerator:
         //      debug information locally variable by a compiler for the tag sequence and annotate point.
        public void CompileToMethod(MethodBuilder method, DebugInfoGenerator debugInfoGenerator);
    }
}
LambdaExpression

  As can be seen from the above expression tree data structure is one level.

  All of expression trees are inherited Expression, the following is a commonly used expression tree types

Let's look at a set of codes

Func<int, int, int> func = (m, n) => m * n + 2;
Expression<Func<int, int, int>> exp = (m, n) => m * n + 2;
int iResult1 = func.Invoke(99, 99);
int iResult2 = exp.Compile().Invoke(99, 99);

  iResult1 and results iResult2 the same, but can Compile () only LambdaExpression. The Compile () Lambda expressions are described expression tree compiler into executable code, and generates a delegate of the lambda expression. . Exp.Compile () Invoke (99,99) corresponding to this call exp.Compile () ();

  We expression tree above about dismantling, according to the priority of the operator, we first calculate the m * n, then the multiplication result is added 2, below.

As shown in the code, m and n are parameters, the type ParameterExpression, 2 is a constant, the constant type ConstantExpression, MultiplyAssign multiplication, Add addition. The sixth step can be performed only represented Lambda expressions expression tree, i.e. LambdaExpression or Expression <TDelegate> type. If the expression tree is not represented Lambda expressions, call the Lambda method to create a new expression. exp.Compile () to delegate, and then call.

       Our expression tree type and then re-package it

{
                    ParameterExpression left = Expression.Parameter(typeof(int), "m");//左边的参数
                    ParameterExpression right = Expression.Parameter(typeof(int), "n");//右边的参数
                    ConstantExpression constantlExp = Expression.Constant(2, typeof(int));//常量2
                    BinaryExpression binaryExpMult = Expression.MultiplyAssign(left, right);//两个参数相乘
                    BinaryExpression binaryExpAdd = Expression.Add(binaryExpMult, constantlExp);//相乘的结果再加2
                    Expression<Func<int, int, int>> actExpression = Expression.Lambda<Func<int, int, int>>(binaryExpAdd, left, right);
                    int result = actExpression.Compile()(2, 1);//调用
                    Console.WriteLine(result + "");
                }
View Code

表达式树的意义:数据化的表达式

我们现在已经能够用两种方式创建表达式树——用Expression的节点组合或者直接从C#、VB的Lambda表达式生成。不管使用的是那种方法,最后我们得到的是一个内存中树状结构的数据。如果我们愿意,可以将它还原成文本源代码的表达式或者序列化到字符串里。注意,如果是C#的表达式本身,我们是没法对它进行输出或者序列化的,它只存在于编译之前的源文件里。现在的表达式树已经成为了一种数据,而不在是语言中的表达式。我们可以在运行的时候处理这一数据,精确了解其内在逻辑;将它传递给其他的程序或者再次编译成为可以执行的代码。这就可以总结为表达式树的三大基本用途:

  • 运行时分析表达式的逻辑
  • 序列化或者传输表达式
  • 重新编译成可执行的代码

 下面我们来实践一下。

  在实际场景中,会有实体与实体之间的转化,如:People类转化成PeopleDto类。

先声明这两个类:

/// <summary>
    /// 实体类
    /// </summary>
    public class People
    {
        public int Age { get; set; }
        public string Name { get; set; }

        public int Id;
    }

    /// <summary>
    /// 实体类Target
    /// </summary>
    public class PeopleDto
    {
        public int Age { get; set; }
        public string Name { get; set; }

        public int Id;
    }
View Code

我们先简单的实现一下

            People people = new People()
                {
                    Id = 11,
                    Name = "Eleven",
                    Age = 31
                };
                PeopleDto peopleCopy = new PeopleDto()
                {
                    Id = people.Id,
                    Name = people.Name,
                    Age = people.Age
                };                

功能是实现了,但是直接写死,以上代码只是对于People类实例people进行转化,但是对于其他实例呢?

我们再用表达式目录树实现一下:

                Expression<Func<People, PeopleDto>> lambda = p =>//表达式目录树  
                        new PeopleDto()
                        {
                            Id = p.Id,
                            Name = p.Name,
                            Age = p.Age
                        };
                lambda.Compile()(people);
View Code

虽然也实现了,但是任然写死了,他只是实现了people类的转化,但是下次换一种类型呢?如果换个Animal类呢?还是要封装一个方法。

其实最好的解决方案是表达目录树+泛型+缓存

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace ExpressionDemo.MappingExtend
{
    /// <summary>
    /// 生成表达式目录树 缓存
    /// </summary>
    public class ExpressionMapper
    {
        private static Dictionary<string, object> _Dic = new Dictionary<string, object>();

        /// <summary>
        /// 字典缓存表达式树
        /// </summary>
        /// <typeparam name="TIn"></typeparam>
        /// <typeparam name="TOut"></typeparam>
        /// <param name="tIn"></param>
        /// <returns></returns>
        public static TOut Trans<TIn, TOut>(TIn tIn)
        {
            string key = string.Format("funckey_{0}_{1}", typeof(TIn).FullName, typeof(TOut).FullName);
            if (!_Dic.ContainsKey(key))
            {
                ParameterExpression parameterExpression = Expression.Parameter(typeof(TIn), "p");
                List<MemberBinding> memberBindingList = new List<MemberBinding>();
                foreach (var item in typeof(TOut).GetProperties())
                {
                    MemberExpression property = Expression.Property(parameterExpression, typeof(TIn).GetProperty(item.Name));
                    MemberBinding memberBinding = Expression.Bind(item, property);
                    memberBindingList.Add(memberBinding);
                }
                foreach (var item in typeof(TOut).GetFields())
                {
                    MemberExpression property = Expression.Field(parameterExpression, typeof(TIn).GetField(item.Name));
                    MemberBinding memberBinding = Expression.Bind(item, property);
                    memberBindingList.Add(memberBinding);
                }
                MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TOut)), memberBindingList.ToArray());
                Expression<Func<TIn, TOut>> lambda = Expression.Lambda<Func<TIn, TOut>>(memberInitExpression, new ParameterExpression[]
                {
                    parameterExpression
                });
                Func<TIn, TOut> func = lambda.Compile();//拼装是一次性的
                _Dic[key] = func;
            }
            return ((Func<TIn, TOut>)_Dic[key]).Invoke(tIn);
        }
    }
}

 

Guess you like

Origin www.cnblogs.com/LearnLog/p/11261055.html