• 表达式树中递归方法


           说到递归我们经常用阶乘来做演示,这里我们尝试用表达式树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

  • 相关阅读:
    去掉返回数据存在HTML节点问题
    ios8 地图不能定位问题的解决办法
    日期选择器
    定位的系统实现简单方法
    NSMutableString 的使用例子
    UIImagePickerController--------图片选取器
    代码中判断网络类型的类别
    Gitbook Android App
    Ionic 整合 pixi.js
    ionic app调试问题
  • 原文地址:https://www.cnblogs.com/wintersun/p/2557540.html
Copyright © 2020-2023  润新知