参考博问: 表达式树反射
这个博问的发起者说表达式的性能要高于反射,我也没较真,理论分析,似乎应该高一点的。
但是我的实验却相反:
var paramExp1 = Expression.Parameter(typeof(string), "a"); var method = typeof(string).GetMethod("ToCharArray", new Type[0]); var callExpression = Expression.Call(paramExp1, method); var tmp = 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++) { tmp.DynamicInvoke("aaa"); //method.Invoke("aaa", new object[0]); } expWatch.Stop(); var t1 = methodWatch.ElapsedTicks; var t2 = expWatch.ElapsedTicks;
以上实验,t1的值在1000-2000之间,而t2则在5000-7000之间。
在网上看了一段代码,测试不同性能的,如下:
public class CallTest { class Student { public string Name { get; set; } } static double Test(int loop, Student stu, Func<Student, string> action) { var watch = Stopwatch.StartNew(); string s = null; for (var i = 0; i < loop; i++) s = action(stu); return watch.ElapsedTicks; } static Func<Student, string> NativeGetter() { return s => s.Name; } static Func<Student, string> ReflectedGetter() { var type = typeof(Student); var prop = type.GetProperty("Name"); return s => (string)prop.GetValue(s, null); } static Func<Student, string> EmittedGetter() { var dm = new DynamicMethod(name: "EmittedGetter", returnType: typeof(string), parameterTypes: new[] { typeof(Student) }, owner: typeof(Student)); var type = typeof(Student); var prop = type.GetMethod("get_Name"); var il = dm.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Call, prop); il.Emit(OpCodes.Ret); return (Func<Student, string>)dm.CreateDelegate(typeof(Func<Student, string>)); } static Func<Student, string> ExpressionGetter() { var type = typeof(Student); var prop = type.GetMethod("get_Name"); ParameterExpression pa = Expression.Parameter(typeof(Student)); Expression body = Expression.Call(pa, prop); return Expression.Lambda<Func<Student, string>>(body, pa).Compile(); } static Func<Student, string> DynamicGetter() { return s => { dynamic d = s; return d.Name; }; } [MethodImpl(MethodImplOptions.NoOptimization)] public static void Run() { int loop = 5000000; while (loop > 0) { var stu = new Student { Name = "Mike" }; var dynamic = Test(loop, stu, DynamicGetter()); var expression = Test(loop, stu, ExpressionGetter()); var native = Test(loop, stu, NativeGetter()); var emitted = Test(loop, stu, EmittedGetter()); var reflected = Test(loop, stu, ReflectedGetter()); Console.WriteLine(loop); Console.WriteLine("native:{1}{0}dynamic:{2}{0}emit:{3}{0}expression:{4}{0}reflection:{5}{0}", Environment.NewLine, 1, dynamic / native, emitted / native, expression / native, reflected / native); loop /= 10; } Console.ReadKey(); } }
感觉,expression的性能很稳定,无论5次还是5百万次,都是2倍多点。
我测试了一下,按照你这个写法,大概是5:1 (Expression:Reflect),关注中。
那有纯粹的Expression来替代Reflector?
@519740105: 感觉表达式树比较反人类思维。
如果用于底层,作个ORM啊,或是系统框架之类的,
会好一点,但平时这样编程会把人整疯的。
我对于软件公司的构思,一直是抽象思维的人与具像思维的两组人。
但中间协调的这个如何起作用,一直都有疑惑。唉!
@爱编程的大叔:
把dynamicinvoke修改为直接执行(设置lambda的代理类型能解决):
var del = Expression.Lambda<Func<string, char[]>>(callExpression, new ParameterExpression[] { paramExp1 }).Compile();
从而,可以在调用的时候:
del("aaa");
这样就性能大大提高了。
我再想,怎么把这个过程封装起来,从而提高效率。