说到递归我们经常用阶乘来做演示,这里我们尝试用表达式树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,希望对您开发有帮助。
您可以感兴趣的文章:
作者:Petter Liu
出处:http://www.cnblogs.com/wintersun/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
该文章也同时发布在我的独立博客中-Petter Liu Blog。