2011-10-26 39 views
5

Tôi cố gắng xây dựng một đuôi đệ quy Expression trong .NET 4.0.Tôi có thể xây dựng một cuộc gọi đuôi được gọi là biểu thức tối ưu đệ quy không?

Tôi có thể xây dựng nó nhưng, phương pháp được biên dịch này không được tối ưu hóa cuộc gọi đuôi, mặc dù chỉ định tailCall = true, IL được tạo không có hướng dẫn tiền tố tail..

Vui lòng cho tôi biết cách tạo một cuộc gọi đuôi được tối ưu hóa đệ quy Expression?

Biểu thức xây dựng bên dưới.

using System; 
using System.Linq.Expressions; 

namespace ConsoleApplication2 
{ 
    public delegate int RecursiveFunc(RecursiveFunc function, int acc, int n); 

    internal class Program 
    { 
     private static void Main() 
     { 
      var funcParam = Expression.Parameter(typeof (RecursiveFunc)); 
      var accParam = Expression.Parameter(typeof (int)); 
      var nParam = Expression.Parameter(typeof (int)); 
      var constZero = Expression.Constant(0, typeof (int)); 

      var accumExpr = Expression.Add(accParam, nParam); 
      var decrimentExpr = Expression.Decrement(nParam); 

      var invokeExpr = Expression.Invoke(funcParam, funcParam, 
       accumExpr, decrimentExpr); 

      var testExpr = Expression.Equal(nParam, constZero); 
      var condExpr = Expression.Condition(testExpr, accParam, 
       invokeExpr); 

      var lambda = Expression.Lambda<RecursiveFunc>(condExpr, 
       "TailCall", true, new[] {funcParam, accParam, nParam}); 

      var sumParam = Expression.Parameter(typeof (RecursiveFunc), 
       "Sum"); 

      var method = lambda.Compile(); 

      var ans = method(method, 0, 100); 
      Console.WriteLine(ans); 
     } 
    } 
} 

Và expresion lambda này tạo ra IL dưới

.method public static int32 EvaluateTarget (
    class [ConsoleApplication2]ConsoleApplication2.RecursiveFunc '', 
    int32 '', 
    int32 '' 
) cil managed 
{ 
    // Method begins at RVA 0x2050 
    // Code size 25 (0x19) 
    .maxstack 7 

    IL_0000: ldarg.2 
    IL_0001: ldc.i4.0 
    IL_0002: ceq 
    IL_0004: brfalse IL_000b 

    IL_0009: ldarg.1 
    IL_000a: ret 

    IL_000b: ldarg.0 
    IL_000c: ldarg.0 
    IL_000d: ldarg.1 
    IL_000e: ldarg.2 
    IL_000f: add 
    IL_0010: ldarg.2 
    IL_0011: ldc.i4.1 
    IL_0012: sub 
    IL_0013: callvirt instance int32 
     [ConsoleApplication2]ConsoleApplication2.RecursiveFunc::Invoke(class 
     [ConsoleApplication2]ConsoleApplication2.RecursiveFunc, int32, int32) 
    IL_0018: ret 
} // end of method AutoGeneratedType::EvaluateTarget 
+1

Bạn nên đăng một số mã mà bạn đang sử dụng để tạo ra các biểu hiện. Thật khó để nói chắc chắn. – casperOne

+0

Cảm ơn lời khuyên của bạn. Và tôi thêm một mã mẫu và biểu thức này được tạo ra IL –

Trả lời

3

Các công trình sau đây xung quanh:

using System; 
using System.Linq.Expressions; 
using System.Reflection.Emit; 

namespace ConsoleApplication2 
{ 
    public delegate int RecursiveFunc(RecursiveFunc doCall, RecursiveFunc function, int acc, int n); 

    internal class Program 
    { 
     private static void Main() 
     { 
      DynamicMethod dm = new DynamicMethod("DoInvokeWithTailCall", typeof(int), new Type[] { typeof(RecursiveFunc), typeof(RecursiveFunc), typeof(int), typeof(int) }, typeof(Program).Module); 
      ILGenerator il = dm.GetILGenerator(); 
      il.Emit(OpCodes.Ldarg_1); 
      il.Emit(OpCodes.Ldarg_0); 
      il.Emit(OpCodes.Ldarg_1); 
      il.Emit(OpCodes.Ldarg_2); 
      il.Emit(OpCodes.Ldarg_3); 
      il.Emit(OpCodes.Tailcall); 
      il.EmitCall(OpCodes.Callvirt, typeof(RecursiveFunc).GetMethod("Invoke"), null); 
      il.Emit(OpCodes.Ret); 
      RecursiveFunc doCall = (RecursiveFunc)dm.CreateDelegate(typeof(RecursiveFunc)); 

      var doCallParam = Expression.Parameter(typeof(RecursiveFunc)); 
      var funcParam = Expression.Parameter(typeof(RecursiveFunc)); 
      var accParam = Expression.Parameter(typeof(int)); 
      var nParam = Expression.Parameter(typeof(int)); 
      var constZero = Expression.Constant(0, typeof(int)); 

      var accumExpr = Expression.Add(accParam, nParam); 
      var decrimentExpr = Expression.Decrement(nParam); 

      //var invokeExpr = Expression.Invoke(funcParam, funcParam, funcParam, accumExpr, decrimentExpr); 
      var invokeExpr = Expression.Call(dm, doCallParam, funcParam, accumExpr, decrimentExpr); 

      var testExpr = Expression.Equal(nParam, constZero); 
      var condExpr = Expression.Condition(testExpr, accParam, 
       invokeExpr); 

      var lambda = Expression.Lambda<RecursiveFunc>(condExpr, 
       "TailCall", true, new[] { doCallParam, funcParam, accParam, nParam }); 

      var method = lambda.Compile(); 

      var ans = method(doCall, method, 0, 100); 
      Console.WriteLine(ans); 
     } 
    } 
} 
Các vấn đề liên quan