从网上找的各种Emit自己调整的,说实在话,用的有点迷糊
public static Func<object, object> GetFuncViaEmit(Type TargetType, MethodInfo GetMethod) { DynamicMethod method = new DynamicMethod("GetValue", typeof(object), new Type[] { typeof(object) }, typeof(object), true); ILGenerator ilGenerator = method.GetILGenerator(); ilGenerator.DeclareLocal(typeof(object)); ilGenerator.Emit(OpCodes.Ldarg_0); ilGenerator.Emit(OpCodes.Castclass, TargetType); ilGenerator.EmitCall(OpCodes.Callvirt, GetMethod, null); if (GetMethod.ReturnType.IsValueType) { ilGenerator.Emit(OpCodes.Box, GetMethod.ReturnType); } ilGenerator.Emit(OpCodes.Stloc_0); ilGenerator.Emit(OpCodes.Ldloc_0); ilGenerator.Emit(OpCodes.Ret); method.DefineParameter(1, ParameterAttributes.In, "value"); return (Func<object, object>)method.CreateDelegate(typeof(Func<object, object>)); }
private static void ValueTest(object entity)//object entity可以是匿名类型 { var type = entity.GetType(); var Methods = type.GetMethods(); MethodInfo Method; object Value; foreach (var p in type.GetProperties()) { Method = Methods.First(v => v.Name.ToLower() == "get_" + p.Name.ToLower()); //Value = p.GetValue(entity, null);//直接反射获取 //Value = GetFuncViaEmit(type, Method)(entity)//通过Emit获取 } } }
上面的Emit 和 反射 的哪种效率好,自己在电脑上测试的(插入/更新/查询各10000条数据),基本没什么差别,是测试方法不对么??
是我在哪里理解的不对吗?还是写法上有问题?
求助啊~
private static void ValueTest(object entity)//object entity可以是匿名类型 { var type = entity.GetType(); var Methods = type.GetMethods(); MethodInfo Method; object Value; var fun = GetFuncViaEmit(type, Method); foreach (var p in type.GetProperties()) { Method = Methods.First(v => v.Name.ToLower() == "get_" + p.Name.ToLower()); //Value = p.GetValue(entity, null);//直接反射获取 //Value =func(entity)//通过Emit获取 } } }
你的代码Emit每次都是重新创建,性能很低,建议创建后缓存起来,你按上面的代码重新试试看就知道了。
Method 在 for外还没赋值,是不能那样用的~
@.攀攀灬.: 那你可以考虑优化一下流程,保证Emit创建的方法能被缓存,速度会提高很多。
@F9:正常的项目中已经缓存了IL,可是我想知道的是在这里为什么emit会和反射一样效率,理论上说应该比反射更快些才对啊
@.攀攀灬.:
public class EmitTest { Func<T, object> GetEmitMethod<T>(MethodInfo method) { DynamicMethod getValue = new DynamicMethod("GetValue", typeof(object), new Type[] { typeof(T) }, true); ILGenerator generator = getValue.GetILGenerator(); generator.DeclareLocal(typeof(object)); generator.Emit(OpCodes.Nop); generator.Emit(OpCodes.Ldarg_0); generator.Emit(OpCodes.Callvirt, method); generator.Emit(OpCodes.Stloc_0); var label = generator.DefineLabel(); generator.Emit(OpCodes.Br_S, label); generator.MarkLabel(label); generator.Emit(OpCodes.Ldloc_0); generator.Emit(OpCodes.Ret); return (Func<T, object>)getValue.CreateDelegate(typeof(Func<T, object>)); } [TestMethod] public void Test() { var type = typeof(EmitDemo); var property = type.GetProperty("Name"); var func = GetEmitMethod<EmitDemo>(property.GetGetMethod()); int count = 1000000; var item = new EmitDemo() { Name = "Hello" }; Stopwatch watch = new Stopwatch(); watch.Start(); for (int i = 0; i < count; i++) { func(item); } watch.Stop(); Console.WriteLine("EMIT:{0}", watch.ElapsedMilliseconds); watch.Reset(); watch.Start(); for (int i = 0; i < count; i++) { property.GetValue(item, null); } watch.Stop(); Console.WriteLine("反射:{0}", watch.ElapsedMilliseconds); } public object GetName(EmitDemo item) { return item.Name; } } public class EmitDemo { public string Name { get; set; } }
不确定你的实际测试的代码是什么情况,如果确实有做缓存,是不可能没有性能差别的。
上面的代码你可以实际运行测试一下,反射是直接用的PropertyInfo.GetValue方法取值,Emit构建的代码跟GetName方法是一样的,执行100万次后得到的结果是
Emit:8,反射:228。
@F9: 你的写法只能得到"Name"属性的,我想要的肯定是类的所有字段,不过还是要谢谢你
@.攀攀灬.: 亲,我这里的代码只是给你一个示范和对比,说明两种方法的性能差别,你实际用肯定是需要调整的,按照类似的思路实现再测试一下,效果可能没有我给的示例差异那么大,但是至少不会是两种实现性能差不多的。