@@ -22,24 +22,65 @@ public int Run()
22
22
[ Test ]
23
23
public void Test_Recursive_Expression ( )
24
24
{
25
- var expr = MakeFactorialExpression < int > ( ) ;
25
+ var expr = MakeFactorialExpressionWithTheTrick < int > ( ) ;
26
26
27
27
expr . PrintCSharp ( ) ;
28
28
var fs = expr . CompileSys ( ) ;
29
29
fs . PrintIL ( ) ;
30
30
var res = fs ( 4 ) ;
31
31
32
- var f = expr . CompileFast ( true , CompilerFlags . NoInvocationLambdaInlining ) ;
32
+ var f = expr . CompileFast ( true ) ;
33
33
f . PrintIL ( ) ;
34
34
var res2 = f ( 4 ) ;
35
35
36
- // f = expr.CompileFast(true);
37
- // f.PrintIL();
38
- // res2 = f(4);
39
-
40
36
Assert . AreEqual ( res , res2 ) ;
41
37
}
42
38
39
+ public Expression < Func < T , T > > MakeFactorialExpressionWithTheTrick < T > ( )
40
+ {
41
+ var nParam = Expression . Parameter ( typeof ( T ) , "n" ) ;
42
+ var methodVar = Expression . Variable ( typeof ( Func < T , T > ) , "fac" ) ;
43
+ var methodsVar = Expression . Variable ( typeof ( Func < T , T > [ ] ) , "facs" ) ;
44
+ var one = Expression . Constant ( 1 , typeof ( T ) ) ;
45
+
46
+ // This does not work:
47
+ // Func<int, int> rec = null;
48
+ // Func<int, int> tmp = n => n <= 1 ? 1 : n * rec(n - 1);
49
+ // rec = tmp; // setting the closure variable! means that this closure variable is not readonly
50
+
51
+ // This should work:
52
+ // var recs = new Func<int, int>[1];
53
+ // Func<int, int> tmp = n => n <= 1 ? 1 : n * recs[0](n - 1);
54
+ // recs[0] = tmp; // setting the item inside the closure variable of array type should work because of reference semantic
55
+
56
+
57
+ return Expression . Lambda < Func < T , T > > (
58
+ Expression . Block (
59
+ new [ ] { methodsVar , methodVar } ,
60
+ Expression . Assign ( methodsVar , Expression . NewArrayBounds ( typeof ( Func < T , T > ) , Expression . Constant ( 1 ) ) ) ,
61
+ Expression . Assign (
62
+ methodVar ,
63
+ Expression . Lambda < Func < T , T > > (
64
+ Expression . Condition (
65
+ // ( n <= 1 )
66
+ Expression . LessThanOrEqual ( nParam , one ) ,
67
+ // 1
68
+ one ,
69
+ // n * method( n - 1 )
70
+ Expression . Multiply (
71
+ // n
72
+ nParam ,
73
+ // method( n - 1 )
74
+ Expression . Invoke (
75
+ Expression . ArrayIndex ( methodsVar , Expression . Constant ( 0 ) ) ,
76
+ Expression . Subtract ( nParam , one ) ) ) ) ,
77
+ nParam ) ) ,
78
+ Expression . Assign ( Expression . ArrayAccess ( methodsVar , Expression . Constant ( 0 ) ) , methodVar ) ,
79
+ // return method( n );
80
+ Expression . Invoke ( methodVar , nParam ) ) ,
81
+ nParam ) ;
82
+ }
83
+
43
84
//from https://chriscavanagh.wordpress.com/2012/06/18/recursive-methods-in-expression-trees/
44
85
public Expression < Func < T , T > > MakeFactorialExpression < T > ( )
45
86
{
0 commit comments