说到递归我们经常用阶乘来做演示,这里我们尝试用表达式树ExpressionTree实现它,假设您已经了解CSharp语言

        /// <summary>
        /// Makes the factorial expression.
        /// </summary>
        /// <typeparam name="T">T</typeparam>
        /// <returns>Expression<Func<T, T>> </returns>
        public Expression<Func<T, T>> MakeFactorialExpression<T>()
        {
            var nParam = Expression.Parameter(typeof(T), "n");
            var methodVar = Expression.Variable(typeof(Func<T, T>), "factorial");
            var one = Expression.Convert(Expression.Constant(1), typeof(T));
 
            return Expression.Lambda<Func<T, T>>(
                Expression.Block(
                // Func<uint, uint> method;
                    new[] { methodVar },
                // method = n => ( n <= 1 ) ? 1 : n * method( n - 1 );
                    Expression.Assign(
                        methodVar,
                        Expression.Lambda<Func<T, T>>(
                            Expression.Condition(
                // ( n <= 1 )
                                Expression.LessThanOrEqual(nParam, one),
                // 1
                                one,
                // n * method( n - 1 )
                                Expression.Multiply(
                // n
                                    nParam,
                // method( n - 1 )
                                    Expression.Invoke(
                                        methodVar,
                                        Expression.Subtract(nParam, one)))),
                            nParam)),
                // return method( n );
                    Expression.Invoke(methodVar, nParam)),
                nParam);
        }

 

生成的IL是这样的:

   1:  .method public hidebysig instance class [System.Core]System.Linq.Expressions.Expression`1<class [mscorlib]System.Func`2<!!T, !!T>> MakeFactorialExpression<T>() cil managed
   2:  {
   3:      .maxstack 12
   4:      .locals init (
   5:          [0] class [System.Core]System.Linq.Expressions.ParameterExpression nParam,
   6:          [1] class [System.Core]System.Linq.Expressions.ParameterExpression methodVar,
   7:          [2] class [System.Core]System.Linq.Expressions.UnaryExpression one,
   8:          [3] class [System.Core]System.Linq.Expressions.Expression`1<class [mscorlib]System.Func`2<!!T, !!T>> CS$1$0000,
   9:          [4] class [System.Core]System.Linq.Expressions.ParameterExpression[] CS$0$0001,
  10:          [5] class [System.Core]System.Linq.Expressions.Expression[] CS$0$0002,
  11:          [6] class [System.Core]System.Linq.Expressions.Expression[] CS$0$0003)
  12:      L_0000: nop 
  13:      L_0001: ldtoken !!T
  14:      L_0006: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
  15:      L_000b: ldstr "n"
  16:      L_0010: call class [System.Core]System.Linq.Expressions.ParameterExpression [System.Core]System.Linq.Expressions.Expression::Parameter(class [mscorlib]System.Type, string)
  17:      L_0015: stloc.0 
  18:      L_0016: ldtoken [mscorlib]System.Func`2<!!T, !!T>
  19:      L_001b: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
  20:      L_0020: ldstr "factorial"
  21:      L_0025: call class [System.Core]System.Linq.Expressions.ParameterExpression [System.Core]System.Linq.Expressions.Expression::Variable(class [mscorlib]System.Type, string)
  22:      L_002a: stloc.1 
  23:      L_002b: ldc.i4.1 
  24:      L_002c: box int32
  25:      L_0031: call class [System.Core]System.Linq.Expressions.ConstantExpression [System.Core]System.Linq.Expressions.Expression::Constant(object)
  26:      L_0036: ldtoken !!T
  27:      L_003b: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
  28:      L_0040: call class [System.Core]System.Linq.Expressions.UnaryExpression [System.Core]System.Linq.Expressions.Expression::Convert(class [System.Core]System.Linq.Expressions.Expression, class [mscorlib]System.Type)
  29:      L_0045: stloc.2 
  30:      L_0046: ldc.i4.1 
  31:      L_0047: newarr [System.Core]System.Linq.Expressions.ParameterExpression
  32:      L_004c: stloc.s CS$0$0001
  33:      L_004e: ldloc.s CS$0$0001
  34:      L_0050: ldc.i4.0 
  35:      L_0051: ldloc.1 
  36:      L_0052: stelem.ref 
  37:      L_0053: ldloc.s CS$0$0001
  38:      L_0055: ldc.i4.2 
  39:      L_0056: newarr [System.Core]System.Linq.Expressions.Expression
  40:      L_005b: stloc.s CS$0$0002
  41:      L_005d: ldloc.s CS$0$0002
  42:      L_005f: ldc.i4.0 
  43:      L_0060: ldloc.1 
  44:      L_0061: ldloc.0 
  45:      L_0062: ldloc.2 
  46:      L_0063: call class [System.Core]System.Linq.Expressions.BinaryExpression [System.Core]System.Linq.Expressions.Expression::LessThanOrEqual(class [System.Core]System.Linq.Expressions.Expression, class [System.Core]System.Linq.Expressions.Expression)
  47:      L_0068: ldloc.2 
  48:      L_0069: ldloc.0 
  49:      L_006a: ldloc.1 
  50:      L_006b: ldc.i4.1 
  51:      L_006c: newarr [System.Core]System.Linq.Expressions.Expression
  52:      L_0071: stloc.s CS$0$0003
  53:      L_0073: ldloc.s CS$0$0003
  54:      L_0075: ldc.i4.0 
  55:      L_0076: ldloc.0 
  56:      L_0077: ldloc.2 
  57:      L_0078: call class [System.Core]System.Linq.Expressions.BinaryExpression [System.Core]System.Linq.Expressions.Expression::Subtract(class [System.Core]System.Linq.Expressions.Expression, class [System.Core]System.Linq.Expressions.Expression)
  58:      L_007d: stelem.ref 
  59:      L_007e: ldloc.s CS$0$0003
  60:      L_0080: call class [System.Core]System.Linq.Expressions.InvocationExpression [System.Core]System.Linq.Expressions.Expression::Invoke(class [System.Core]System.Linq.Expressions.Expression, class [System.Core]System.Linq.Expressions.Expression[])
  61:      L_0085: call class [System.Core]System.Linq.Expressions.BinaryExpression [System.Core]System.Linq.Expressions.Expression::Multiply(class [System.Core]System.Linq.Expressions.Expression, class [System.Core]System.Linq.Expressions.Expression)
  62:      L_008a: call class [System.Core]System.Linq.Expressions.ConditionalExpression [System.Core]System.Linq.Expressions.Expression::Condition(class [System.Core]System.Linq.Expressions.Expression, class [System.Core]System.Linq.Expressions.Expression, class [System.Core]System.Linq.Expressions.Expression)
  63:      L_008f: ldc.i4.1 
  64:      L_0090: newarr [System.Core]System.Linq.Expressions.ParameterExpression
  65:      L_0095: stloc.s CS$0$0001
  66:      L_0097: ldloc.s CS$0$0001
  67:      L_0099: ldc.i4.0 
  68:      L_009a: ldloc.0 
  69:      L_009b: stelem.ref 
  70:      L_009c: ldloc.s CS$0$0001
  71:      L_009e: call class [System.Core]System.Linq.Expressions.Expression`1<!!0> [System.Core]System.Linq.Expressions.Expression::Lambda<class [mscorlib]System.Func`2<!!T, !!T>>(class [System.Core]System.Linq.Expressions.Expression, class [System.Core]System.Linq.Expressions.ParameterExpression[])
  72:      L_00a3: call class [System.Core]System.Linq.Expressions.BinaryExpression [System.Core]System.Linq.Expressions.Expression::Assign(class [System.Core]System.Linq.Expressions.Expression, class [System.Core]System.Linq.Expressions.Expression)
  73:      L_00a8: stelem.ref 
  74:      L_00a9: ldloc.s CS$0$0002
  75:      L_00ab: ldc.i4.1 
  76:      L_00ac: ldloc.1 
  77:      L_00ad: ldc.i4.1 
  78:      L_00ae: newarr [System.Core]System.Linq.Expressions.Expression
  79:      L_00b3: stloc.s CS$0$0003
  80:      L_00b5: ldloc.s CS$0$0003
  81:      L_00b7: ldc.i4.0 
  82:      L_00b8: ldloc.0 
  83:      L_00b9: stelem.ref 
  84:      L_00ba: ldloc.s CS$0$0003
  85:      L_00bc: call class [System.Core]System.Linq.Expressions.InvocationExpression [System.Core]System.Linq.Expressions.Expression::Invoke(class [System.Core]System.Linq.Expressions.Expression, class [System.Core]System.Linq.Expressions.Expression[])
  86:      L_00c1: stelem.ref 
  87:      L_00c2: ldloc.s CS$0$0002
  88:      L_00c4: call class [System.Core]System.Linq.Expressions.BlockExpression [System.Core]System.Linq.Expressions.Expression::Block(class [mscorlib]System.Collections.Generic.IEnumerable`1<class [System.Core]System.Linq.Expressions.ParameterExpression>, class [System.Core]System.Linq.Expressions.Expression[])
  89:      L_00c9: ldc.i4.1 
  90:      L_00ca: newarr [System.Core]System.Linq.Expressions.ParameterExpression
  91:      L_00cf: stloc.s CS$0$0001
  92:      L_00d1: ldloc.s CS$0$0001
  93:      L_00d3: ldc.i4.0 
  94:      L_00d4: ldloc.0 
  95:      L_00d5: stelem.ref 
  96:      L_00d6: ldloc.s CS$0$0001
  97:      L_00d8: call class [System.Core]System.Linq.Expressions.Expression`1<!!0> [System.Core]System.Linq.Expressions.Expression::Lambda<class [mscorlib]System.Func`2<!!T, !!T>>(class [System.Core]System.Linq.Expressions.Expression, class [System.Core]System.Linq.Expressions.ParameterExpression[])
  98:      L_00dd: stloc.3 
  99:      L_00de: br.s L_00e0
 100:      L_00e0: ldloc.3 
 101:      L_00e1: ret 
 102:  }
 103:   

接着看单元测试:

        [TestMethod]
        public void TestMakeFactorialExpression()
        {
            var factorial = MakeFactorialExpression<uint>().Compile();
            var result = factorial(5);
            uint expectedResult=120;
            Assert.AreEqual(expectedResult, result);
        }

 

很简单, 更多您可以参考MSDN,希望对您开发有帮助。

您可以感兴趣的文章:

.net3.5下使用LINQ递归算法实现简洁代码

 


作者:Petter Liu
出处:http://www.cnblogs.com/wintersun/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
该文章也同时发布在我的独立博客中-Petter Liu Blog

posted on 2012-06-21 12:00  PetterLiu  阅读(1742)  评论(0编辑  收藏  举报