艾伟:表达式树和泛型委托

什么是表达式树?

  表达式树又称为表达式目录树,以数据形式表示语言级代码。所有的数据都存储在树结构中,每个结点表示一个表达式(Expression)。要想手动生成表达式树我们需要引用System.Linq.Expressions 命名空间,最重要的一个类是Expression,它是所有表达式的基类。例如:

  1:参数表达式:ParameterExpression,就是一个方法中的参数,例如 search(string key),key可以看成是一个参数表达式。

  2:二元表达式:BinaryExpression,例如a+b等。

  3:方法调用表达式:MethodCallExpression,例如:自定义LINQ提供程序中实现orderby 的操作:

MethodCallExpression orderByCallExpression = Expression.Call(
                typeof(Queryable),
                "OrderBy",
                new Type[] { queryableData.ElementType, queryableData.ElementType
 },
                whereCallExpression,
                Expression.Lambda<Func<string, string>>(pe, new ParameterExpression
[] { pe }));

  4:常数表达式:ConstantExpression,例如数值5。

  5:字段或属性表达式:MemberExpression,例如str.Length。Expression.Property(pe,   typeof(string).GetProperty("Length"));

  6:带有条件运算的表达式:ConditionalExpression。

  7:描述lambda表达式:LambdaExpression

  8:一元运算符的表达式:UnaryExpression

  9:表达式和类型之间的相关操作:TypeBinaryExpression等等,它们都继承Expression。

泛型委托:

  表达式树经常与泛型委托一起使用,这里简单介绍下什么是泛型委托。Func<(Of <(T, TResult>)>) 泛型委托:封装一个具有一个参数并返回 TResult 参数指定的类型值的方法。如果想增加参数可以写成Func<(Of <(T1,T2, TResult>)>) 等。这种方法比起传统的显示声明委托的方法从代码结构上要简化不少,我们不用特意去申请一个delegate,所有的委托都可以用泛型委托来代替。这里简单来实现一个算术表达式来说明泛型委托的好处。

  算术表达:(a+b)^b

  1:传统的显示申明委托方式。

  1):申明一个委托:

/// 
    /// (a+b)^b 委托
    /// 
    /// para 1
    /// para 2
    /// 
    public delegate double PowerCompute(double num_1, double num_2);

  2):编码委托对应的方法体

/// 
        /// (a+b)^b方法
        /// 
        /// para 1
        /// para 2
        /// 
        public static  double GetPowerCompute(double num_1, double num_2)
        {
            return Math.Pow((num_1 + num_2), num_2);
        }

  3):调用:

double dResult = 0;
            PowerCompute pc = GetPowerCompute;
            dResult = pc(2, 2);
            Console.WriteLine(dResult.ToString());

  2:泛型委托实现:

  1):编码委托对应的方法体,方法同上面代码中第二步。

  2):调用

Func<double ,double ,double > fc=GetPowerCompute;
            dResult = fc(2, 2);
            Console.WriteLine(dResult.ToString());

  表达式树的执行:

  表达式树和泛型委托:   这里实现一个简单的表达式树,实现(a+b)^b, 过程中需要知道以下三个比较重要的方法。

  1:Expression<(Of <(TDelegate>)>) :以表达式目录树的形式将强类型 lambda 表达式表示为数据结构。

  2: Expression.Lambda方法:创建一个表示 lambda 表达式的表达式目录树。

  3:Expression<(Of <(TDelegate>)>).Compile :将表达式目录树描述的 lambda 表达式编译为可执行代码。

  下面是(a+b)^b的表达式树生成可执行代码并且在客户端进行调用的代码:

ParameterExpression penum_1 = Expression.Parameter(typeof(double), "num_1");
            ParameterExpression penum_2 = Expression.Parameter(typeof(double),
"num_2");
            BinaryExpression _be = Expression.Add(penum_1, penum_2);
            BinaryExpression _be2 = Expression.Power(_be, penum_2);
            Expression<Func<double, double, double>> ef = Expression.Lambda<Func
<double, double, double>>(_be2, new ParameterExpression[] { 

penum_1, penum_2 });
            Func<double, double, double> cf = ef.Compile();
            return cf(num_1 ,num_2 );

下面是(a+b)^b的表达式树的关系图

表达式树的修改:

  表达式目录树是不可变的,这意味着不能直接修改表达式目录树。若要更改表达式目录树,必须创建现有表达式目录树的一个副本,并在创建副本的过程中执行所需更改。您可以使用表达式目录树访问器遍历现有表达式目录树,并复制它访问的每个节点。我们可以创建自定义类来继承ExpressionVisitor,在自定义类中重定相应方式来达到修改表达式树的目的。 

时间: 2024-09-17 17:02:49

艾伟:表达式树和泛型委托的相关文章

表达式树和泛型委托

什么是表达式树? 表达式树又称为表达式目录树,以数据形式表示语言级代码.所有的数据都存储在树结构中,每个结点表示一个表达式(Expression).要想手动生成表达式树我们需要引用System.Linq.Expressions 命名空间,最重要的一个类是Expression,它是所有表达式的基类.例如: 1:参数表达式:ParameterExpression,就是一个方法中的参数,例如 search(string key),key可以看成是一个参数表达式. 2:二元表达式:BinaryExpre

C#中表达式树和反射来访问对象属性的性能比较浅析

今天在工作上遇到这么个需求:需要获取对象上所有属性的值,但并事先并不知道对象的类型. 我的第一反应就是使用反射,但是这个操作会进行多次,大量的反射肯定会有性能影响.虽然对我这个项目无关紧要,但我还是选择了另外一种解决方案:构建表达式树,再生成委托,然后将委托缓存在字典里.代码如下: 首先构建表达式树(类似这种形式:'(a) => a.xx'),并生成委托:    代码如下 复制代码 private static Delegate BuildDynamicGetPropertyValueDeleg

LINQ表达式树基础

刚接触LINQ的人往往觉得表达式树很不容易理解.通过这篇文章我希望大家 看到它其实并不像想象中那么难.您只要有普通的LINQ知识便可以轻松理解本文 . 表达式树提供一个将可执行代码转换成数据的方法.如果你要在执行代码之 前修改或转换此代码,那么它是非常有价值的.尤其是当你要将C#代码----如 LINQ查询表达式转换成其他代码在另一个程序----如SQL数据库里操作它. 但是我在这里颠倒顺序,在文章最后你很容易发现为什么将代码转换到数据 中去很有用.首先我需要提供一点背景知识.让我们开始看看相关

Lambda表达式表达式树

在C#3.0中,继匿名方法之后出现了Lambda 表达式,使表达更为简洁.快捷.Lambda 表达式使用Lambda 运算符 "=>"来定义,语法如下: (参数列表) => {方法体} Lambda 运算符的左边是输入参数,定义Lambda表达式的接收参数列表,右边包含表达式或语句块,表示将表达式的值或语句块返回的值传给左边的参数列表. Lambda 表达式是一个匿名函数,可以包含表达式和语句,并且可用于创建委托或表达式目录树类型. 以下部分来自MSDN:点击打开链接 La

C# 3.0语言新特性(语言规范):8 表达式树

规范 原文:<C# Version 3.0 Specification>,Microsoft翻译:lover_P 表达式树允许将拉姆达表达式表现为数据结构而不是可执行代码.一个可以转换为委托类型D的拉姆达表达式也可以转换为一个类型为System.Query.Expression<D>的表达式树.将一个拉姆达表达式转换为委托类型导致可执行代码被委托所生成和引用,而将其转换为一个表达式树类型将导致创建了表达式树实例的代码被发出(Emit).表达式树是拉姆达表达式的一种高效的内存中(in

C#委托基础5——泛型委托Action

C#委托基础系列原于2011年2月份发表在我的新浪博客中,现在将其般至本博客.本文参考自金旭亮老师的<.NET 4.0面向对象编程漫谈>有关代理的内容   为了方便开发,.NET基类库针对在实际开发中最常用的情形提供了几个预定义好的委托,这些预定义委托用得很广,比如在编写lambda表达式和开发并行计算程序时经常要用到他们 对于函数返回值为空的情形,可以使用Action泛型委托 class Program { // 对于函数返回值为空的情形,可以使用Action泛型委托 void Showst

C# 参考:令人惊喜的泛型委托 Predicate/Func/Action

Predicate 泛型委托   表示定义一组条件并确定指定对象是否符合这些条件的方法.此委托由 Array 和 List 类的几种方法使用,用于在集合中搜索元素. 看看下面它的定义:     // Summary:    //     Represents the method that defines a set of criteria and determines whether    //     the specified object meets those criteria.   

C#委托基础4——泛型委托Func

C#委托基础系列原于2011年2月份发表在我的新浪博客中,现在将其般至本博客. 为了方便开发,.NET基类库针对在实际开发中最常用的情形提供了几个预定义好的委托,这些预定义委托用得很广,比如在编写lambda表达式和开发并行计算程序时经常要用到他们.   预定义泛型委托Func class Program { double AddInt(int x, int y) { return x + y; } string AddString(string s1, string s2) { return

C#委托基础3——泛型委托

C#委托基础系列原于2011年2月份发表在我的新浪博客中,现在将其般至本博客.   泛型委托 class Program { // 泛型委托,与普通委托类似,不同之处只在于使用泛型委托要指定泛型参数 public delegate T MyGenericDelegate<T>(T obj1,T obj2); int AddInt(int x, int y) { return x + y; } string AddString(string s1, string s2) { return s1