对于.NET/Expression编程国内的话并没有过多相关的文献 相对的大多数人对于表达式树的动态编程几乎闻所未闻 至于别人看不看我并不在意
Expression<Action> e = Expression.Lambda<Action>(
Expression.Call(typeof(Console).GetMethod("WriteLine", new[] { typeof(string) }),
Expression.Constant("hello world!"))
);
e.Compile()();
上述是一个调用“Console::WriteLine”打印“hello world!”的表达式代码,你可以很轻易的看清楚它的组成部分~那么这句话等同于什么?
即“Console.WriteLine("
hello world!
");”
那么这上面的代码包含什么意义?实际上它并没有多大的意义 只是做为一个基础的认识 那么linq表达式它可以做什么?
我举个例子应该有人涉猎过“数据仓储”这个东西 它可以把C#/VB.NET语言的Lambda表达式块转换成对应的DI-SQL查询语句
Lambda表达式是可以与“Expression”进行静态的隐式转换的(编译器支持)但这包含很多限制条件 先看看如下的可被允许的代码
Expression<Action> e = () => Console.WriteLine("hello world!");
那么如下的语句则是不被允许的 C#语言编译器无法转换下类明确标明花括号的Lambda表达式代码块的转换
Expression<Action> e = () =>
{
Console.WriteLine("hello world!");
};
同时另一个极强的限制则在于 它无法定义局部的变量 即由编译器支持的Lambda表达式与动态表达式的静态转换 同时对于编译器支持的最大的问题则在于不可动态性 因为代码是固定的
但这些限制对于 你编写动态的Expression会有用?答案是否定的、对于表达式树编程或者称元数据表达式编程而言 它可以绕过安全机制访问在代码域内可以访问到的任何成员 如类型、方法、字段、属性、局部变量、参数等等 这些都是它的一大不错的优势 这大大的提高了它的可想象性
private static string mPrintText = "hello world!";
static void Main(string[] args)
{
Expression<Action> e = () => Console.WriteLine(mPrintText);
e.Compile()();
}
如上则是一个很形象的例子,它访问了一个私有的成员 并且成功的执行那句表达式 上面这么写这个例子会更加清晰易懂 当然随着后面深入下去 向这么编写表达式的几率基本为零
那么向上述的表达式书写 适合哪一些目标?比如你编写了一个关于数据库操作的ORM框架 其中有这么一条方法“Find”此时编写了一句表达式为“FindAll((user) => user.ID >= 0 && user.ID <= 5);” 即查询“user”表中满足
“ID” >= 0 And “ID <= 5”的所有记录
而你是可以从代码上动态解析这串表达式的,在VS中有一个很好用的功能 即表达式的DebugView它可以很清晰的显示你的表达式的代码结构视图
那么“Expression.Reduce()”方法是用于实现或移植其动态语言到.NET上的人。他们可以创建自己的表达式节点, 也可以 "减少" 到标准表达式树节点, 并都可以进行编译。而且在表达式树 api 中是具备了一些 "可还原"
节点的,在一般情况下 是不需要手动的“Reduce(简化)”的 在此处“Reduce”的含义是(简化)而不是(归纳)