代码改变世界

(转)Expression Tree不完全入门

2011-07-26 22:01  音乐让我说  阅读(323)  评论(0编辑  收藏  举报

在.NET Framework 3.5中提供了表达式目录树(Expression Tree),它是一种抽象语法树或者说它是一种数据结构。在了解他之前我们需要从委托说起,
在.NET中委托是使用delegate 关键字声明的一个引用类型,类似于 C++ 中的函数指针,你可以把委托理解为方法的别名,只不过他代表了一类的方法。
委托是类型安全和可靠的。

1.我们举一个例子来简单说明委托的使用,假设我们有一个人员组织库,我们要列出库中所有人员的名字,下面是代码:

public class Employe
    {
        public string Name { get; set; }
        public int Age { get; set; }

        public Employe(string name,int age)
        {
            this.Name = name;
            this.Age = age;
        }
    }
public delegate void ProcessEmployeDelegate(Employe emp);
    
public class EmpDataBase
{
        List<Employe> list = new List<Employe> 
        {
            new Employe("Cary",25),
            new Employe("James",34)
        };
        
        public void ProcessEmploye(ProcessEmployeDelegate processEmploye)
        {
            foreach (Employe emp in list)
            {
                processEmploye(emp);
            }
        }
}

 

class Program
{        
        static void ShowEmpName(Employe emp)
        {            
            "名字:{0}".FormatWriteLine(emp.Name);
        }
     
        static void Main()
        {            
            EmpDataBase empdb = new EmpDataBase();
            empdb.ProcessEmploye(ShowEmpName);
}

}

下面是结果:

名字:Cary
名字:James

上面我为String加了一个简单的扩展方法,代码如下:

public static void FormatWriteLine(this string format, params object[] args)
{
     Console.WriteLine(string.Format(format, args));
}
2.到.NET2.0时代,引入了匿名方法,使用匿名方法我们就不必创建单独的方法,而是将匿名方法直接作为参数传递。于是上面的主程序就可以改变为如下代码:
class Program
{        
       static void Main()
        {            
            EmpDataBase empdb = new EmpDataBase();
            empdb.ProcessEmploye(delegate(Employe emp)
            {
                "名字:{0}".FormatWriteLine(emp.Name);
            });
}
}
3.进入.NET3.X时代,我们又有了Lambda表达,可以将delegate关键字也去掉,让人彻底的看不见委托的影子,代码如下:
class Program
{        
        static void Main()
        {            
            EmpDataBase empdb = new EmpDataBase();
            empdb.ProcessEmploye(emp=>"名字:{0}".FormatWriteLine(emp.Name));
}
}
4.到此为止我们的主程序是不是简化了许多。不过我们还声明了一个ProcessEmployeDelegate委托,我们可以使用Action<T>或Func来代替,Action<T>
和Func<T,TResult>的功能没有什么区别,只是Action<T>没有返类型。代码如下:
public void ProcessEmploye(Action<Employe> processEmploye)
{
      foreach (Employe emp in list)
      {
           processEmploye(emp);
      }
}

 

5.了解了lambda表达式,其对应的具体语法树就是Expression Tree,其对应的相关API都在System.Linq.Expressions命名空间下,如下图:

http://images.cnblogs.com/cnblogs_com/carysun/WindowsLiveWriter/Expression_8A94/image_2.png

我们来看下Expression类的结构,该类有四个属性:

  Body:获取表达式的主体;
  Parameters:获取Lambda表达示的参数;
  NodeType:得到树中某些节点的表达式类型(ExpressionType),这是一个有45种不同值的枚举类型,代表表达式节点的所有可能类型,如返回常数、
                         也可能返回参数、或者返回一个值是否小于另外一个(<),或者返回一个值是否大于另外一个(>),或者返回两个值的和( )等等。
  Type:得到表达式的静态类型,在本例中,表达式的类型是Func。

6.我们构建,遍历,修改表达式目录树,还可以执行表达式目录树,下面继续举几个例子来说明。找出下面字符串数字中以“C”开头的员工(x => x.StartsWith("C")):

String[] names = new string[2] { "Cary","James"};
Expression<Func<String, Boolean>>  expression1 = (x) => x.StartsWith("C");
"Expression is {0}\r\n".FormatWriteLine(expression1.ToString());          
foreach (String name in  names.Where(expression1.Compile()))
{        
    "{0 }".FormatWriteLine(name);
}

 

7.找出人员库中年龄为25的员工,表达式为:Expression is age => (age.Age = 25)

ConstantExpression constEmpAge = Expression.Constant(25);
ParameterExpression paramAge =Expression.Parameter(typeof(Employe), "age");
MemberExpression mex =LambdaExpression.PropertyOrField(paramAge, "Age");

BinaryExpression filter = Expression.Equal(mex, constEmpAge);
Expression<Func<Employe, bool>> expression2 = Expression.Lambda<Func<Employe, bool>>
  (filter,new ParameterExpression[] { paramAge });            
"Expression is {0}\r\n".FormatWriteLine(expression2.ToString());
foreach (Employe emp in list.Where(expression2.Compile()))
{
      "{0}:{1}".FormatWriteLine(emp.Name,emp.Age);
}

 

8.我们还可以使用Expression Tree Visualizer来查看表达式目录树的相关信息,如下图:

http://images.cnblogs.com/cnblogs_com/carysun/WindowsLiveWriter/Expression_8A94/image_thumb_1.png

Expression Tree Visualizer的使用将ExpressionTreeVisualizer中的.dll文件拷贝到..\Program Files\Microsoft Visual Studio 9.0\Common7\Packages\Debugger\Visualizers.中。

本文没有过多深入的内容,只是希望给大家带来一些对Expression的基本认识,希望本文能对您有用。

转载自:http://www.cnblogs.com/carysun/archive/2009/11/15/ExpressionTree.html

谢谢浏览!