首页 新闻 会员 周边

帮忙看看这两种写法 哪个性能好,Emit 反射GetValue(object,nulll)

0
悬赏园豆:60 [已关闭问题] 关闭于 2015-09-02 17:58

从网上找的各种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条数据),基本没什么差别,是测试方法不对么??

是我在哪里理解的不对吗?还是写法上有问题?

求助啊~

问题补充:

就没有高手过来给看看╭( T □ T )╮

.攀攀灬的主页 .攀攀灬 | 初学一级 | 园豆:161
提问于:2015-07-24 18:23
< >
分享
所有回答(1)
0
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每次都是重新创建,性能很低,建议创建后缓存起来,你按上面的代码重新试试看就知道了。

I,Robot | 园豆:9783 (大侠五级) | 2015-07-24 18:51

Method 在 for外还没赋值,是不能那样用的~

支持(0) 反对(0) .攀攀灬 | 园豆:161 (初学一级) | 2015-07-24 22:52

@.攀攀灬.: 那你可以考虑优化一下流程,保证Emit创建的方法能被缓存,速度会提高很多。

支持(0) 反对(0) I,Robot | 园豆:9783 (大侠五级) | 2015-07-25 07:20

@F9:正常的项目中已经缓存了IL,可是我想知道的是在这里为什么emit会和反射一样效率,理论上说应该比反射更快些才对啊

支持(0) 反对(0) .攀攀灬 | 园豆:161 (初学一级) | 2015-07-25 12:22

@.攀攀灬.: 

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。

支持(0) 反对(0) I,Robot | 园豆:9783 (大侠五级) | 2015-07-25 16:37

@F9: 你的写法只能得到"Name"属性的,我想要的肯定是类的所有字段,不过还是要谢谢你

支持(0) 反对(0) .攀攀灬 | 园豆:161 (初学一级) | 2015-07-28 14:07

@.攀攀灬.: 亲,我这里的代码只是给你一个示范和对比,说明两种方法的性能差别,你实际用肯定是需要调整的,按照类似的思路实现再测试一下,效果可能没有我给的示例差异那么大,但是至少不会是两种实现性能差不多的。

支持(0) 反对(0) I,Robot | 园豆:9783 (大侠五级) | 2015-07-28 20:19
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册