在.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 |
上面我为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命名空间下,如下图:
我们来看下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来查看表达式目录树的相关信息,如下图:
Expression Tree Visualizer的使用将ExpressionTreeVisualizer中的.dll文件拷贝到..\Program Files\Microsoft Visual Studio 9.0\Common7\Packages\Debugger\Visualizers.中。
本文没有过多深入的内容,只是希望给大家带来一些对Expression的基本认识,希望本文能对您有用。