利用表达式树构建委托改善反射性能 分类: .NET 2014-02-20 10:34 348人阅读 评论(0) 收藏 .Net4.0反射性能改善 改善老赵的DynamicMethodExecutor 构建委托动态赋值 ===重要更新===
最近搞一个系统时由于在比较关键地方用到反射了,所以要关注了一下反射的性能问题。搜索一下,不难搜到老赵的这篇文章,下面是一些杂乱的笔记。(建议先看老赵的文章)
看老赵的文章,老赵得到的结果是这样的:
1
2
3
|
00:00:00.0125539
(Directly invoke)
00:00:04.5349626
(Reflection invoke)
00:00:00.0322555
(Dynamic executor)
|
而我把代码搞下来自己运行得到这样的结果:
1
2
3
|
00:00:00.0009710
(Directly invoke)
00:00:00.4142893
(Reflection invoke)
00:00:00.0194501
(Dynamic executor)
|
这里不是说机器性能造成绝对的时间,而是差距比例完全不一样,想了一阵想起了老赵当时应该是基于.Net3.5,果断把程序的目标框架切换到.Net3.5,结果如下:
1
2
3
|
00:00:00.0018801
(Directly invoke)
00:00:02.4288876
(Reflection invoke)
00:00:00.0141537
(Dynamic executor)
|
改善老赵的DynamicMethodExecutor
老赵的那篇的文章的思路是使用DynamicMethodExecutor来构造一个万能的委托Func<object, object[], object>其中第一个参数是实例对象,第二是参数列表,第三是返回值。.Net4.0的表达式树要比3.5的先进一点,经过一番改造发现是不需要这么一个万能委托的,直接用Expression.Lambda.Compile()编译出来的Delegate强制转换为强类型的委托来得更加简单。全部代码一个方法即可,精简了许多。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
///
<summary>
///
动态构造委托
///
</summary>
///
<param name="methodInfo">方法元数据</param>
///
<returns>委托</returns>
public static Delegate
BuildDynamicDelegate(MethodInfo methodInfo)
{
if (methodInfo
== null )
throw new ArgumentNullException( "methodInfo" );
var paramExpressions
= methodInfo.GetParameters().Select((p, i) =>
{
var name
= "param" +
(i + 1).ToString(CultureInfo.InvariantCulture);
return Expression.Parameter(p.ParameterType,
name);
}).ToList();
MethodCallExpression
callExpression;
if (methodInfo.IsStatic)
{
//Call(params....)
callExpression
= Expression.Call(methodInfo, paramExpressions);
}
else
{
var instanceExpression
= Expression.Parameter(methodInfo.ReflectedType, "instance" );
//insatnce.Call(params….)
callExpression
= Expression.Call(instanceExpression, methodInfo, paramExpressions);
paramExpressions.Insert(0,
instanceExpression);
}
var lambdaExpression
= Expression.Lambda(callExpression, paramExpressions);
return lambdaExpression.Compile();
}
|
使用时转换为强类型的委托即可:
1
2
|
var action
= (Action<TInstance, T1, T2>)BuildDynamicDelegate(methodInfo);
var func
= (Func<TInstance, T1, T2, TReturn>)BuildDynamicDelegate(methodInfo);
|
老赵那个委托都是object,使用时的类型转换,还有装箱,拆箱都会有一定的性能损失,而强类型就没有这个问题。
首先在老赵的那篇文章上一个方法改为两个方法,然后测试:
1
2
|
public void Call1( object o1,
object o2,
object o3)
{ }
public void Call2( int o1,
int o2,
int o3)
{ }
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
private static void DynamicExecutor_ObjectType()
{
var executor
= new DynamicMethodExecutor(Call1MethodInfo);
var watch1
= new Stopwatch();
watch1.Start();
for ( var i
= 0; i < Times; i++)
{
executor.Execute(ProgramInstance,
ObjectParameters);
}
watch1.Stop();
Console.WriteLine(watch1.Elapsed
+ "
(Dynamic executor(object))(JeffreyZhao)" );
}
private static void DynamicExecutor_IntType()
{
var executor
= new DynamicMethodExecutor(Call2MethodInfo);
var watch1
= new Stopwatch();
watch1.Start();
for ( var i
= 0; i < Times; i++)
{
executor.Execute(ProgramInstance,
IntParameters);
}
watch1.Stop();
Console.WriteLine(watch1.Elapsed
+ "
(Dynamic executor(int))(JeffreyZhao)" );
}
private static void DynamicExecutor_StrongObject()
{
var action
= DynamicMethodBuilder.BuildAction<Program, object ,
object ,
object >(Call1MethodInfo);
var watch1
= new Stopwatch();
watch1.Start();
for ( var i
= 0; i < Times; i++)
{
action(ProgramInstance,
ObjectParameters[0], ObjectParameters[1], ObjectParameters[2]);
}
watch1.Stop();
Console.WriteLine(watch1.Elapsed
+ "
(Dynamic executor(object))(zhangweiwen)" );
}
private static void DynamicExecutor_StrongInt()
{
var action
= DynamicMethodBuilder.BuildAction<Program, int ,
int ,
int >(Call2MethodInfo);
var watch1
= new Stopwatch();
watch1.Start();
for ( var i
= 0; i < Times; i++)
{
action(ProgramInstance,
IntParameters1[0], IntParameters1[1], IntParameters1[2]);
}
watch1.Stop();
Console.WriteLine(watch1.Elapsed
+ "
(Dynamic executor(int))(zhangweiwen)" );
}
|
结果:
1
2
3
4
|
00:00:00.0188422
(Dynamic executor( object ))(JeffreyZhao)
00:00:00.0210869
(Dynamic executor( int ))(JeffreyZhao)
00:00:00.0142841
(Dynamic executor( object ))(zhangweiwen)
00:00:00.0147589
(Dynamic executor( int ))(zhangweiwen)
|
差距不大,但是还是有一定得改善,特别参数是int的方法,用了强类型后性能比较稳定,不会出现偏差。
构建委托动态赋值
既然有动态调用方法,同样也可以动态赋值,而且据我的经验,根据PropertyInfo的SetValue去反射设属性值用得比反射调用方法更加频繁。所以同样需要有方法来动态构建委托改善性能。
幸好,.Net4.0提供了支持,.Net4.0新增了Expression.Assign来表示一个赋值表达式。有了它,构建起来比方法的更加简单:
1
2
3
4
5
6
7
8
9
10
11
|
private static Action<TInstance,
TProperty> BuildSetPropertyAction<TInstance, TProperty>(PropertyInfo propertyInfo)
{
var instanceParam
= Expression.Parameter( typeof (TInstance),
"instance" );
var valueParam
= Expression.Parameter( typeof (TProperty),
"value" );
//instance.Property
var propertyProperty
= Expression.Property(instanceParam, propertyInfo);
//instance.Property
= value
var assignExpression
= Expression.Assign(propertyProperty, valueParam);
var lambdaExpression
= Expression.Lambda<Action<TInstance, TProperty>>(assignExpression, instanceParam, valueParam);
return lambdaExpression.Compile();
}
|
直接返回了强类型的委托,所以使用起来更加简单:
1
2
|
var action
= BuildSetPropertyAction<Program, object >(ObjectPropertyInfo);
action(ProgramInstance,
ObjectValue);
|
来测试一下性能:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
|
private static void DirectlySetValueType()
{
var watch1
= new Stopwatch();
watch1.Start();
for ( var i
= 0; i < Times; i++)
{
ProgramInstance.IntProperty
= IntValue;
}
watch1.Stop();
Console.WriteLine(watch1.Elapsed
+ "
(Directly Set IntProperty)" );
}
private static void ReflectionSetValueType()
{
var watch2
= new Stopwatch();
watch2.Start();
for ( var i
= 0; i < Times; i++)
{
IntPropertyInfo.SetValue(ProgramInstance,
IntValue, null );
}
watch2.Stop();
Console.WriteLine(watch2.Elapsed
+ "
(Reflection Set IntProperty)" );
}
private static void DynamicSetValueType()
{
var action
= BuildSetPropertyAction<Program, int >(IntPropertyInfo);
var watch1
= new Stopwatch();
watch1.Start();
for ( var i
= 0; i < Times; i++)
{
action(ProgramInstance,
IntValue);
}
watch1.Stop();
Console.WriteLine(watch1.Elapsed
+ "
(Dynamic Set IntProperty)" );
}
private static void DirectlySetReferenceType()
{
var watch1
= new Stopwatch();
watch1.Start();
for ( var i
= 0; i < Times; i++)
{
ProgramInstance.ObjectProperty
= ObjectValue;
}
watch1.Stop();
Console.WriteLine(watch1.Elapsed
+ "
(Directly Set ObjectProperty)" );
}
private static void ReflectionSetReferenceType()
{
var watch2
= new Stopwatch();
watch2.Start();
for ( var i
= 0; i < Times; i++)
{
ObjectPropertyInfo.SetValue(ProgramInstance,
ObjectValue, null );
}
watch2.Stop();
Console.WriteLine(watch2.Elapsed
+ "
(Reflection Set ObjectProperty)" );
}
private static void DynamicSetReferenceType()
{
var action
= BuildSetPropertyAction<Program, object >(ObjectPropertyInfo);
//action(ProgramInstance,
ObjectValue);
var watch1
= new Stopwatch();
watch1.Start();
for ( var i
= 0; i < Times; i++)
{
action(ProgramInstance,
ObjectValue);
}
watch1.Stop();
Console.WriteLine(watch1.Elapsed
+ "
(Dynamic Set ObjectProperty)" );
}
|
结果如下:
1
2
3
4
5
6
7
8
|
Test
Set Value:
00:00:00.0003237
(Directly Set IntProperty)
00:00:00.3160570
(Reflection Set IntProperty)
00:00:00.0132668
(Dynamic Set IntProperty)
-----
00:00:00.0028183
(Directly Set ObjectProperty)
00:00:00.2937783
(Reflection Set ObjectProperty)
00:00:00.0150118
(Dynamic Set ObjectProperty)
|
虽然跟直接赋值不能比,但比反射快大概30倍。
全部代码
希望对大家有帮助
The End。
===重要更新===
我把上面的方法用在项目中才发现陷入了一个悖论。就是往往需要使用反射的上下文中是没有实例类型的,而有了实例类型的上下文中有往往不需要反射。所以构建表达式树是需要去掉实例的类型参数,在表达式树中做类型转换,这样会有一点点的性能损失,但同时又带来一个好处,使用时类型参数少了一个,写起来方便了一点。两个主要代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
///
<summary>
///
动态构造委托
///
</summary>
///
<param name="methodInfo">方法元数据</param>
///
<returns>委托</returns>
public static Delegate
BuildDynamicDelegate(MethodInfo methodInfo)
{
if (methodInfo
== null )
throw new ArgumentNullException( "methodInfo" );
var paramExpressions
= methodInfo.GetParameters().Select((p, i) =>
{
var name
= "param" +
(i + 1).ToString(CultureInfo.InvariantCulture);
return Expression.Parameter(p.ParameterType,
name);
}).ToList();
MethodCallExpression
callExpression;
if (methodInfo.IsStatic)
{
//Call(params....)
callExpression
= Expression.Call(methodInfo, paramExpressions);
}
else
{
var instanceExpression
= Expression.Parameter( typeof ( object ),
"instance" );
//((T)instance)
var castExpression
= Expression.Convert(instanceExpression, methodInfo.ReflectedType);
//((T)instance).Call(params)
callExpression
= Expression.Call(castExpression, methodInfo, paramExpressions);
paramExpressions.Insert(0,
instanceExpression);
}
var lambdaExpression
= Expression.Lambda(callExpression, paramExpressions);
return lambdaExpression.Compile();
}
//使用
public static Action< object >
BuildAction(MethodInfo methodInfo)
{
return (Action< object >)BuildDynamicDelegate(methodInfo);
}
public static Action< object ,
T1> BuildAction<T1>(MethodInfo methodInfo)
{
return (Action< object ,
T1>)BuildDynamicDelegate(methodInfo);
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
///
<summary>
///
动态构造赋值委托
///
</summary>
///
<typeparam name="TProperty">属性类型</typeparam>
///
<param name="propertyInfo">属性元数据</param>
///
<returns>强类型委托</returns>
public static Action< object ,
TProperty> BuildSetPropertyAction<TProperty>(PropertyInfo propertyInfo)
{
var instanceParam
= Expression.Parameter( typeof ( object ),
"instance" );
var valueParam
= Expression.Parameter( typeof (TProperty),
"value" );
//((T)instance)
var castExpression
= Expression.Convert(instanceParam, propertyInfo.ReflectedType);
//((T)instance).Property
var propertyProperty
= Expression.Property(castExpression, propertyInfo);
//((T)instance).Property
= value
var assignExpression
= Expression.Assign(propertyProperty, valueParam);
var lambdaExpression
= Expression.Lambda<Action< object ,
TProperty>>(assignExpression, instanceParam, valueParam);
return lambdaExpression.Compile();
}
//使用
var action
= BuildSetPropertyAction< int >(IntPropertyInfo);
action(ProgramInstance,
IntValue);
|
最近搞一个系统时由于在比较关键地方用到反射了,所以要关注了一下反射的性能问题。搜索一下,不难搜到老赵的这篇文章,下面是一些杂乱的笔记。(建议先看老赵的文章)
看老赵的文章,老赵得到的结果是这样的:
1
2
3
|
00:00:00.0125539
(Directly invoke)
00:00:04.5349626
(Reflection invoke)
00:00:00.0322555
(Dynamic executor)
|
而我把代码搞下来自己运行得到这样的结果:
1
2
3
|
00:00:00.0009710
(Directly invoke)
00:00:00.4142893
(Reflection invoke)
00:00:00.0194501
(Dynamic executor)
|
这里不是说机器性能造成绝对的时间,而是差距比例完全不一样,想了一阵想起了老赵当时应该是基于.Net3.5,果断把程序的目标框架切换到.Net3.5,结果如下:
1
2
3
|
00:00:00.0018801
(Directly invoke)
00:00:02.4288876
(Reflection invoke)
00:00:00.0141537
(Dynamic executor)
|
改善老赵的DynamicMethodExecutor
老赵的那篇的文章的思路是使用DynamicMethodExecutor来构造一个万能的委托Func<object, object[], object>其中第一个参数是实例对象,第二是参数列表,第三是返回值。.Net4.0的表达式树要比3.5的先进一点,经过一番改造发现是不需要这么一个万能委托的,直接用Expression.Lambda.Compile()编译出来的Delegate强制转换为强类型的委托来得更加简单。全部代码一个方法即可,精简了许多。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
///
<summary>
///
动态构造委托
///
</summary>
///
<param name="methodInfo">方法元数据</param>
///
<returns>委托</returns>
public static Delegate
BuildDynamicDelegate(MethodInfo methodInfo)
{
if (methodInfo
== null )
throw new ArgumentNullException( "methodInfo" );
var paramExpressions
= methodInfo.GetParameters().Select((p, i) =>
{
var name
= "param" +
(i + 1).ToString(CultureInfo.InvariantCulture);
return Expression.Parameter(p.ParameterType,
name);
}).ToList();
MethodCallExpression
callExpression;
if (methodInfo.IsStatic)
{
//Call(params....)
callExpression
= Expression.Call(methodInfo, paramExpressions);
}
else
{
var instanceExpression
= Expression.Parameter(methodInfo.ReflectedType, "instance" );
//insatnce.Call(params….)
callExpression
= Expression.Call(instanceExpression, methodInfo, paramExpressions);
paramExpressions.Insert(0,
instanceExpression);
}
var lambdaExpression
= Expression.Lambda(callExpression, paramExpressions);
return lambdaExpression.Compile();
}
|
使用时转换为强类型的委托即可:
1
2
|
var action
= (Action<TInstance, T1, T2>)BuildDynamicDelegate(methodInfo);
var func
= (Func<TInstance, T1, T2, TReturn>)BuildDynamicDelegate(methodInfo);
|
老赵那个委托都是object,使用时的类型转换,还有装箱,拆箱都会有一定的性能损失,而强类型就没有这个问题。
首先在老赵的那篇文章上一个方法改为两个方法,然后测试:
1
2
|
public void Call1( object o1,
object o2,
object o3)
{ }
public void Call2( int o1,
int o2,
int o3)
{ }
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
private static void DynamicExecutor_ObjectType()
{
var executor
= new DynamicMethodExecutor(Call1MethodInfo);
var watch1
= new Stopwatch();
watch1.Start();
for ( var i
= 0; i < Times; i++)
{
executor.Execute(ProgramInstance,
ObjectParameters);
}
watch1.Stop();
Console.WriteLine(watch1.Elapsed
+ "
(Dynamic executor(object))(JeffreyZhao)" );
}
private static void DynamicExecutor_IntType()
{
var executor
= new DynamicMethodExecutor(Call2MethodInfo);
var watch1
= new Stopwatch();
watch1.Start();
for ( var i
= 0; i < Times; i++)
{
executor.Execute(ProgramInstance,
IntParameters);
}
watch1.Stop();
Console.WriteLine(watch1.Elapsed
+ "
(Dynamic executor(int))(JeffreyZhao)" );
}
private static void DynamicExecutor_StrongObject()
{
var action
= DynamicMethodBuilder.BuildAction<Program, object ,
object ,
object >(Call1MethodInfo);
var watch1
= new Stopwatch();
watch1.Start();
for ( var i
= 0; i < Times; i++)
{
action(ProgramInstance,
ObjectParameters[0], ObjectParameters[1], ObjectParameters[2]);
}
watch1.Stop();
Console.WriteLine(watch1.Elapsed
+ "
(Dynamic executor(object))(zhangweiwen)" );
}
private static void DynamicExecutor_StrongInt()
{
var action
= DynamicMethodBuilder.BuildAction<Program, int ,
int ,
int >(Call2MethodInfo);
var watch1
= new Stopwatch();
watch1.Start();
for ( var i
= 0; i < Times; i++)
{
action(ProgramInstance,
IntParameters1[0], IntParameters1[1], IntParameters1[2]);
}
watch1.Stop();
Console.WriteLine(watch1.Elapsed
+ "
(Dynamic executor(int))(zhangweiwen)" );
}
|
结果:
1
2
3
4
|
00:00:00.0188422
(Dynamic executor( object ))(JeffreyZhao)
00:00:00.0210869
(Dynamic executor( int ))(JeffreyZhao)
00:00:00.0142841
(Dynamic executor( object ))(zhangweiwen)
00:00:00.0147589
(Dynamic executor( int ))(zhangweiwen)
|
差距不大,但是还是有一定得改善,特别参数是int的方法,用了强类型后性能比较稳定,不会出现偏差。
构建委托动态赋值
既然有动态调用方法,同样也可以动态赋值,而且据我的经验,根据PropertyInfo的SetValue去反射设属性值用得比反射调用方法更加频繁。所以同样需要有方法来动态构建委托改善性能。
幸好,.Net4.0提供了支持,.Net4.0新增了Expression.Assign来表示一个赋值表达式。有了它,构建起来比方法的更加简单:
1
2
3
4
5
6
7
8
9
10
11
|
private static Action<TInstance,
TProperty> BuildSetPropertyAction<TInstance, TProperty>(PropertyInfo propertyInfo)
{
var instanceParam
= Expression.Parameter( typeof (TInstance),
"instance" );
var valueParam
= Expression.Parameter( typeof (TProperty),
"value" );
//instance.Property
var propertyProperty
= Expression.Property(instanceParam, propertyInfo);
//instance.Property
= value
var assignExpression
= Expression.Assign(propertyProperty, valueParam);
var lambdaExpression
= Expression.Lambda<Action<TInstance, TProperty>>(assignExpression, instanceParam, valueParam);
return lambdaExpression.Compile();
}
|
直接返回了强类型的委托,所以使用起来更加简单:
1
2
|
var action
= BuildSetPropertyAction<Program, object >(ObjectPropertyInfo);
action(ProgramInstance,
ObjectValue);
|
来测试一下性能:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
|
private static void DirectlySetValueType()
{
var watch1
= new Stopwatch();
watch1.Start();
for ( var i
= 0; i < Times; i++)
{
ProgramInstance.IntProperty
= IntValue;
}
watch1.Stop();
Console.WriteLine(watch1.Elapsed
+ "
(Directly Set IntProperty)" );
}
private static void ReflectionSetValueType()
{
var watch2
= new Stopwatch();
watch2.Start();
for ( var i
= 0; i < Times; i++)
{
IntPropertyInfo.SetValue(ProgramInstance,
IntValue, null );
}
watch2.Stop();
Console.WriteLine(watch2.Elapsed
+ "
(Reflection Set IntProperty)" );
}
private static void DynamicSetValueType()
{
var action
= BuildSetPropertyAction<Program, int >(IntPropertyInfo);
var watch1
= new Stopwatch();
watch1.Start();
for ( var i
= 0; i < Times; i++)
{
action(ProgramInstance,
IntValue);
}
watch1.Stop();
Console.WriteLine(watch1.Elapsed
+ "
(Dynamic Set IntProperty)" );
}
private static void DirectlySetReferenceType()
{
var watch1
= new Stopwatch();
watch1.Start();
for ( var i
= 0; i < Times; i++)
{
ProgramInstance.ObjectProperty
= ObjectValue;
}
watch1.Stop();
Console.WriteLine(watch1.Elapsed
+ "
(Directly Set ObjectProperty)" );
}
private static void ReflectionSetReferenceType()
{
var watch2
= new Stopwatch();
watch2.Start();
for ( var i
= 0; i < Times; i++)
{
ObjectPropertyInfo.SetValue(ProgramInstance,
ObjectValue, null );
}
watch2.Stop();
Console.WriteLine(watch2.Elapsed
+ "
(Reflection Set ObjectProperty)" );
}
private static void DynamicSetReferenceType()
{
var action
= BuildSetPropertyAction<Program, object >(ObjectPropertyInfo);
//action(ProgramInstance,
ObjectValue);
var watch1
= new Stopwatch();
watch1.Start();
for ( var i
= 0; i < Times; i++)
{
action(ProgramInstance,
ObjectValue);
}
watch1.Stop();
Console.WriteLine(watch1.Elapsed
+ "
(Dynamic Set ObjectProperty)" );
}
|
结果如下:
1
2
3
4
5
6
7
8
|
Test
Set Value:
00:00:00.0003237
(Directly Set IntProperty)
00:00:00.3160570
(Reflection Set IntProperty)
00:00:00.0132668
(Dynamic Set IntProperty)
-----
00:00:00.0028183
(Directly Set ObjectProperty)
00:00:00.2937783
(Reflection Set ObjectProperty)
00:00:00.0150118
(Dynamic Set ObjectProperty)
|
虽然跟直接赋值不能比,但比反射快大概30倍。
全部代码
希望对大家有帮助
The End。
===重要更新===
我把上面的方法用在项目中才发现陷入了一个悖论。就是往往需要使用反射的上下文中是没有实例类型的,而有了实例类型的上下文中有往往不需要反射。所以构建表达式树是需要去掉实例的类型参数,在表达式树中做类型转换,这样会有一点点的性能损失,但同时又带来一个好处,使用时类型参数少了一个,写起来方便了一点。两个主要代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
///
<summary>
///
动态构造委托
///
</summary>
///
<param name="methodInfo">方法元数据</param>
///
<returns>委托</returns>
public static Delegate
BuildDynamicDelegate(MethodInfo methodInfo)
{
if (methodInfo
== null )
throw new ArgumentNullException( "methodInfo" );
var paramExpressions
= methodInfo.GetParameters().Select((p, i) =>
{
var name
= "param" +
(i + 1).ToString(CultureInfo.InvariantCulture);
return Expression.Parameter(p.ParameterType,
name);
}).ToList();
MethodCallExpression
callExpression;
if (methodInfo.IsStatic)
{
//Call(params....)
callExpression
= Expression.Call(methodInfo, paramExpressions);
}
else
{
var instanceExpression
= Expression.Parameter( typeof ( object ),
"instance" );
//((T)instance)
var castExpression
= Expression.Convert(instanceExpression, methodInfo.ReflectedType);
//((T)instance).Call(params)
callExpression
= Expression.Call(castExpression, methodInfo, paramExpressions);
paramExpressions.Insert(0,
instanceExpression);
}
var lambdaExpression
= Expression.Lambda(callExpression, paramExpressions);
return lambdaExpression.Compile();
}
//使用
public static Action< object >
BuildAction(MethodInfo methodInfo)
{
return (Action< object >)BuildDynamicDelegate(methodInfo);
}
public static Action< object ,
T1> BuildAction<T1>(MethodInfo methodInfo)
{
return (Action< object ,
T1>)BuildDynamicDelegate(methodInfo);
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
///
<summary>
///
动态构造赋值委托
///
</summary>
///
<typeparam name="TProperty">属性类型</typeparam>
///
<param name="propertyInfo">属性元数据</param>
///
<returns>强类型委托</returns>
public static Action< object ,
TProperty> BuildSetPropertyAction<TProperty>(PropertyInfo propertyInfo)
{
var instanceParam
= Expression.Parameter( typeof ( object ),
"instance" );
var valueParam
= Expression.Parameter( typeof (TProperty),
"value" );
//((T)instance)
var castExpression
= Expression.Convert(instanceParam, propertyInfo.ReflectedType);
//((T)instance).Property
var propertyProperty
= Expression.Property(castExpression, propertyInfo);
//((T)instance).Property
= value
var assignExpression
= Expression.Assign(propertyProperty, valueParam);
var lambdaExpression
= Expression.Lambda<Action< object ,
TProperty>>(assignExpression, instanceParam, valueParam);
return lambdaExpression.Compile();
}
//使用
var action
= BuildSetPropertyAction< int >(IntPropertyInfo);
action(ProgramInstance,
IntValue);
|