User u = new User(); var method = u.GetType().GetMethod("Methods"); var type1 = method.GetParameters()[0].ParameterType; var parameter1 = Expression.Parameter(type1, "pr1"); var type2 = method.GetParameters()[1].ParameterType; var parameter2 = Expression.Parameter(type2, "pr2"); var callExpression = Expression.Call(Expression.Constant(u), method, new Expression[] { parameter1, parameter2 }); Expression<Action<string, int>> scall = Expression.Lambda<Action<string, int>>(callExpression, new ParameterExpression[] { parameter1, parameter2 }); var executeMethods = scall.Compile(); executeMethods("1", 1); u.Methods("ddd", 3);
public class User { public void Methods(string name,int age) { Console.WriteLine(name+"-----"+age+s); } }
这几天学习看了资料 利用表达式树反射?
感觉这样写好麻烦啊?有帮忙优化一下的 或者改进的吗?
为什么要用表达式树?如果你有特别的需求,你可以用表达式树,对于你的这个代码,直接一个method.Invoke就解决了。
嗯 你说的对
原因是 听说效率比传统的反射高。
@s_p: 这个不一定就高哦,别“听说”。而且,即便真的高,又能高多少?相比你的这段代码的编写与执行,这个效率已经降低了很多了。
@519740105: 我有测试 看到过 不是瞎扯的
@s_p: 我说的“别听说”的意思是这个效率影响不是非常的大,除非是实时系统。综合成本考虑,该用哪个。
另外,既然你要考虑到这个性能,那么,表达式的麻烦也就是你必须接受的。
@s_p: 跟你探讨一个问题,你说使用expression调用实体方法比通过反射调用方法性能要高,但我做了个实验:
var paramExp1 = Expression.Parameter(typeof(string), "a"); var method = typeof(string).GetMethod("ToCharArray", new Type[0]); var callExpression = Expression.Call(paramExp1, method); var del = Expression.Lambda(callExpression, paramExp1).Compile(); Stopwatch methodWatch = new Stopwatch(); methodWatch.Start(); for(int i = 0; i < 1000; i++) { method.Invoke("aaa", new object[0]); } methodWatch.Stop(); Stopwatch expWatch = new Stopwatch(); expWatch.Start(); for (int i = 0; i < 1000; i++) { del.DynamicInvoke("aaa"); } expWatch.Stop(); var t1 = methodWatch.ElapsedTicks; var t2 = expWatch.ElapsedTicks;
行为很简单,就是把一个字符串转换为字符数组(调用String.ToCharArray()方法),但结果是:
t2远远大于t1(几次实验,t1都是1000-2000,而t2都是5000-7000)。
你能把你说的那个“看到过”的例子贴出来或发给我吗?
谢谢!
@519740105:
var paramExp1 = Expression.Parameter(typeof(string), "a"); var method = typeof(string).GetMethod("ToCharArray", new Type[0]); var callExpression = Expression.Call(paramExp1, method); var del = Expression.Lambda<Func<string,char[]>>(callExpression, new ParameterExpression[] { paramExp1 }).Compile();; Stopwatch methodWatch = new Stopwatch(); methodWatch.Start(); for (int i = 0; i < 1000; i++) { method.Invoke("aaa", new object[0]); } methodWatch.Stop(); Stopwatch expWatch = new Stopwatch(); expWatch.Start(); for (int i = 0; i < 1000; i++) { del("aaa"); } expWatch.Stop(); var t1 = methodWatch.ElapsedTicks; var t2 = expWatch.ElapsedTicks; Console.WriteLine(t1); Console.WriteLine(t2);
我改成这样你看下
@s_p: 你的代码这笔了,只是以下代码:
var tmp = Expression.Lambda<Func<string,char[]>>(callExpression, new ParameterExpression[] { paramExp1 }).Compile();
的改变吗?我这里得到的结果还是很悬殊,还是t2大!
@519740105: 你把我改的运行下 我这里是t2 小啊 我发图了
@s_p: 恩搞明白了,是调用的时候,直接当作lambda表达式调用,而不是用动态调用。
@519740105: 你把那个循环去掉你看时间 t2是0 O(∩_∩)O~
@s_p: 已经知道了,因为我还是用的DynamicInvoke,没注意你的代码del("aaa")。
@519740105: 嗯 我也只是懂一些基本的 这个太复杂的看不懂 你有什么好的资料没!
@s_p: 木有,研究ing
什么需求?对象能直接实例化出来,为什么要这样绕一大圈调用对象的成员方法呢
原因是 听说效率比传统的高。 不知道合理不还有一个就是自己 喜欢多看看
加油学。
感觉学这个的少啊 有点难 朋友
想要比传统反射效率高,var executeMethods = scall.Compile();你必须把编译得到的executeMethods的这个结果缓存,调用的时候直接调用缓存。
o