前言
刚开始学习编程时,我认为程序带来的价值远不如我为它写的代码多,因为它顶多算加减乘除比一般人快而已,直到我认识了“循环”。而一天后,我又发现程序可以“死循环”,而当时我应付“死循环”的方法是——关机 (- . -!) 狂汗啊!
Loop 循环
这篇文章介绍 Expression Tree 的循环语句:
For,Do,While
。咳咳,应该是Loop!没错,Expreession Tree里没有For,Do,While这些熟悉的朋友,叫了他们的祖先Loop来应付。正如鲁迅那句经典的语录——世界上本没有For,Do,While,程序员写代码写多了烦了,也便有了。
实际上,Loop和Do差不多,它等价于
do{
if(不合适)
break;
}
以下语句可能会有助于你对上述伪代码的理解【未成年的童鞋直接跳到下一段】:不管三七二十一,先do了再说,如果性格不合适就分手。由此可以判断:Loop不是一个专一的家伙。
示例
现在举一个阶乘(如: n!=n*(n-1)*…*2*1)的例子来说明Expreession Tree是如何做循环的。
一般来说,用C#语法是这样写的:
int result = 1; do { result *= n; n--; } while (n > 1);
为了更接近方便构建Expreession Tree,把以上语句改成伪代码格式:
int result = 1; do { if (n > 1) { result *= n; n--; } else { break; } }
对应的表达式树构建:
ParameterExpression value = Expression.Parameter(typeof(int), "value"); ParameterExpression result = Expression.Parameter(typeof(int), "result"); LabelTarget label = Expression.Label(typeof(int)); BlockExpression block = Expression.Block( new[] { result }, Expression.Assign(result, Expression.Constant(1)), Expression.Loop( Expression.IfThenElse( Expression.GreaterThan(value, Expression.Constant(1)), Expression.MultiplyAssign(result, Expression.PostDecrementAssign(value)), Expression.Break(label, result) ), label ) ); Expression<Func<int, int>> lambda = Expression.Lambda<Func<int, int>>(block, value); Func<int, int> func = lambda.Compile(); Console.WriteLine(func(5));
一般来说,Expression Tree 的循环由Expression.Loop 、 Expression.Break 和 LabelTarget 共同构成,如下面格式:
Expression.Loop( … Expression.Break() …, )
为了确保跑出“死循环”,必须制定一个条件“跳出去”(如 Break 和 LabelTarget)。
另外, Expression.MultiplyAssign(result, Expression.PostDecrementAssign(value)) 所表达的就是result *= n--; 也就是 result *= n; n—; 合并成一个语句而已。
总结
值得思考 Expression 里为什么没有For这样常用的方法?
这里埋下伏笔,其实我很早就写好了For,在我自定义的FluentExpression里的写法大概是这样子,以后会详细介绍。
FluentExpression.For(n, n.Assign(2), n <= to, n.PostIncrementAssign() …)