AutoMap Relatively poor performance

Dec 18, 2012 at 11:47 AM

Please try the following code

public static Action<object, object[]> CreatePropertiesAction(PropertyInfo[] infos)
        {
            Type classType = GetClassTypeByProperty(infos);
            DynamicMethod method = new DynamicMethod("", null, new Type[] { typeof(object), typeof(object[]) }, true);
            ILGenerator il = method.GetILGenerator();

            LocalBuilder obj = il.DeclareLocal(classType);
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Unbox_Any, classType); //��Ҫ��ֵ�Ķ�����в���
            il.Emit(OpCodes.Stloc_0); 

            for (int i = 0; i < infos.Length; i++)
            {
                Label lbl_end = il.DefineLabel();
                Type propType = infos[i].PropertyType;

                il.Emit(OpCodes.Ldarg_1);
                Ldc(il, i);
                il.Emit(OpCodes.Ldelem_Ref); //��λi����value

                il.Emit(OpCodes.Ldnull);
                il.Emit(OpCodes.Ceq);
                il.Emit(OpCodes.Brtrue_S, lbl_end); //�ж��Ƿ�Ϊnull��Ϊnull������

                il.Emit(OpCodes.Ldloc_0); //����ѹջ
                il.Emit(OpCodes.Ldarg_1); //ֵ����ѹջ
                Ldc(il, i);               //ѹ������
                il.Emit(OpCodes.Ldelem_Ref); //ȡ��������ֵ
                il.Emit(OpCodes.Unbox_Any, propType); //����

                il.Emit(OpCodes.Callvirt, infos[i].GetSetMethod()); //�������Ե�set���������Ը�ֵ
                il.MarkLabel(lbl_end);
            }

            il.Emit(OpCodes.Ret);
            return method.CreateDelegate(typeof(Action<object, object[]>)) as Action<object, object[]>;
        }

        public static Func<object, object[]> CreatePropertiesFunc(PropertyInfo[] infos)
        {
            Type classType = GetClassTypeByProperty(infos);
            DynamicMethod method = new DynamicMethod("", typeof(object[]), new Type[] { typeof(object) }, true);
            ILGenerator il = method.GetILGenerator();

            LocalBuilder tmp = il.DeclareLocal(typeof(object));
            LocalBuilder result = il.DeclareLocal(typeof(object[]));

            LocalBuilder obj = il.DeclareLocal(classType);
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Unbox_Any, classType);
            il.Emit(OpCodes.Stloc, obj);

            Ldc(il, infos.Length);
            il.Emit(OpCodes.Newarr, typeof(object));
            il.Emit(OpCodes.Stloc, result); //��ʼ��һ��object����

            for (int i = 0; i < infos.Length; i++)
            {
                il.Emit(OpCodes.Ldloc, obj);
                il.Emit(OpCodes.Callvirt, infos[i].GetGetMethod()); //��ȡ���Ե�ֵ

                if (infos[i].PropertyType.IsValueType)
                    il.Emit(OpCodes.Box, infos[i].PropertyType); //ֵ������װ��

                il.Emit(OpCodes.Stloc, tmp); //���浽��ʱ����

                il.Emit(OpCodes.Ldloc, result);
                Ldc(il, i);
                il.Emit(OpCodes.Ldloc, tmp); //�����������λ�á�ֵ�ֱ�ѹջ
                il.Emit(OpCodes.Stelem_Ref); //��ֵ
            }

            il.Emit(OpCodes.Ldloc, result);
            il.Emit(OpCodes.Ret);

            return method.CreateDelegate(typeof(Func<object, object[]>)) as Func<object, object[]>;
        }

        private static Type GetClassTypeByProperty(PropertyInfo[] infos)
        {
            if (infos == null || infos.Length <= 0)
                throw new ArgumentNullException("infos");

            return infos[0].ReflectedType;
        }

        private static void Ldc(ILGenerator il, int value)
        {
            switch (value)
            {
                case -1:
                    il.Emit(OpCodes.Ldc_I4_M1);
                    return;
                case 0:
                    il.Emit(OpCodes.Ldc_I4_0);
                    return;
                case 1:
                    il.Emit(OpCodes.Ldc_I4_1);
                    return;
                case 2:
                    il.Emit(OpCodes.Ldc_I4_2);
                    return;
                case 3:
                    il.Emit(OpCodes.Ldc_I4_3);
                    return;
                case 4:
                    il.Emit(OpCodes.Ldc_I4_4);
                    return;
                case 5:
                    il.Emit(OpCodes.Ldc_I4_5);
                    return;
                case 6:
                    il.Emit(OpCodes.Ldc_I4_6);
                    return;
                case 7:
                    il.Emit(OpCodes.Ldc_I4_7);
                    return;
                case 8:
                    il.Emit(OpCodes.Ldc_I4_8);
                    return;
            }

            if (value > -129 && value < 128)
                il.Emit(OpCodes.Ldc_I4_S, (sbyte)value);
            else
                il.Emit(OpCodes.Ldc_I4, value);
        }

Coordinator
Dec 30, 2012 at 4:17 PM

Thank you for your post. Your code uses IL Emit which is used by many frameworks as it gives good performance (don't get the overhead of reflection). However is has a big downside, it's unreadable and unmaintainable for 99.9% of the developers out there. Due to this I decided not to add any such code. However are you having performance issues? If so then I will consider it.

 

Regards,

Lars-Erik