2011-10-26 19 views
5

मैं .NET 4.0 में एक पूंछ रिकर्सिव Expression बनाने का प्रयास करता हूं।क्या मैं एक पूंछ कॉल रिकर्सिव अनुकूलित अभिव्यक्ति का निर्माण कर सकता हूं?

मैं इसे बना सकता हूं, लेकिन यह संकलित विधि tailCall = true निर्दिष्ट करने के बावजूद पूंछ-कॉल अनुकूलित नहीं है, जेनरेट आईएल में tail. उपसर्ग निर्देश नहीं है।

कृपया मुझे बताओ कि कैसे एक पूंछ-कॉल पुनरावर्ती Expression अनुकूलित का निर्माण करने की?

बिल्ड अभिव्यक्ति के नीचे है।

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); 
     } 
    } 
} 

और यह लैम्ब्डा expresion उत्पन्न आईएल

.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

आप कुछ कोड है कि आप अभिव्यक्ति उत्पन्न करने के लिए प्रयोग कर रहे हैं पोस्ट करना चाहिए। निश्चित रूप से बताना मुश्किल है। – casperOne

+0

आपकी सलाह धन्यवाद। और मैं एक नमूना कोड जोड़ता हूं और यह अभिव्यक्ति आईएल उत्पन्न करता है –

उत्तर

3

के संबंध में निम्न काम करता है नीचे है:

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); 
     } 
    } 
}