用Emit技术替代反射 C# 之 反射性能优化1 从IDataReader中读取数据实体

  以前在上篇博客说到用表达式来替代反射机制,能够得到较高的性能提高。这篇咱们来讲说用Emit技术来替代反射。html

  System.Reflection.Emit命名空间类可用于动态发出Microsoft中间语言(MSIL)代码,以便生成的代码能够直接执行。反射也用于获取有关类及其成员的信息。换句话说,反射是一种技术,容许您检查描述类型及其成员的元数据,你可能以编程方式访问过组件对象模型类型库, .NET中的反射很是类似,但功能强大且易于使用。使用.NET编译器编译源文件时,编译器会产生源文件中语句中的MSIL代码以及描述文件中定义的类型的元数据。正是这个元数据,.NET中的反射API使你可以检查。在这个System.Reflection命名空间中,有一些类可用于帮助访问程序中固有的结构,好比类、类型、字段、结构、枚举、成员和方法。例如,您使用Type类来标识所反映的类的类型,FieldInfo类表示结构或枚举的字段。MemberInfo类表示反射类的成员,并使用MethodInfo类表示反射类的方法。PrimeRealFipe类表示反射类中的方法的参数。编程

  使用System.Reflection.Emit命名空间类在能够编译时建立代码,但前提是必须懂IL代码。(本文不作IL代码详解,由于我也不会。。。)事实上,你实际编写的是就是幕后的MSIL自己。你可使用反射在内存中定义程序集,为该程序集建立类/模块,而后为该模块建立其余模块成员和新类型。你一样也可使用Emit来构造程序集。Reflection.Emit是一个强大的命名空间,咱们能够在运行时动态地发出瞬态和持久化程序集。Reflection.Emit产生一个低级,语言中立的MSIL。一般,咱们经过将源代码保存到磁盘而后编译该源代码来建立程序集,而后咱们调用咱们须要从该程序集中使用的类的方法,该程序集是在磁盘上编译的。可是你能够想象,这涉及额外的磁盘写入和读取工做!使用反射生成代码,咱们能够省略此开销并当即将操做代码直接发送到内存中。反射发射只不过是直接在代码中编写任何汇编代码,而后即时调用生成的代码。这也并非说反射效率就是高,由于在运行期产生指令也是须要时间,各有优缺点。api

  System.Reflection.Emit命名空间提供用户动态建立.exe文件所需的类。它的类容许编译器或工具发出元数据和MSIL。所以,您能够动态地在磁盘上建立.exe文件,就像运行代码,保存代码并调用编译器来编译代码同样。大多数状况下,您须要此功能和此命名空间用于自定义脚本引擎和编译器。 缓存

Reflection.Emit命名空间有许多可用于重要的的类。如下是两个最重要的:
  • AssemblyBuilder类是在运行时发出代码并具备建立动态模块的方法的任何应用程序的起点。
  • ModuleBuilder类用做在运行时向动态程序集添加类和结构等类型的起点。
  生成MSIL指令的ILGenerator.OpCodes类包括其所需字段中的全部IL指令。MSIL是CLR或中间语言的基本汇编语言的无类型操做代码。当您编写任何C#代码并对其进行编译时,它将首先转换为MSIL。而后,当您在MSIL中调用程序集时,它将以相应的机器语言进行转换和执行。学习MSIL的最简单方法是反汇编您编译的简单代码。您可使用.NET SDK实用程序之一ILDasm.exe(IL反汇编程序)在Vs插件库下载便可,来反汇编任何已编译的.NET代码。

 

  本文经过Emit技术来提升后期绑定对象的性能,尽管您不能像硬绑定那样快速执行调用,但执行效果会比在运行时产生代码在绑定更好。代码基本与前篇博客用lambda表达式树替代反射基本同样,核心代码替换过来便可,以下:性能优化

 

    public class PropertyEmit
    {

        private PropertySetterEmit setter;
        private PropertyGetterEmit getter;
        public String PropertyName { get; private set; }
        public PropertyInfo Info { get; private set; }

        public PropertyEmit(PropertyInfo propertyInfo)
        {
            if (propertyInfo == null)
            {
                throw new ArgumentNullException("属性不能为空");
            }

            if (propertyInfo.CanWrite)
            {
                setter = new PropertySetterEmit(propertyInfo);
            }

            if (propertyInfo.CanRead)
            {
                getter = new PropertyGetterEmit(propertyInfo);
            }

            this.PropertyName = propertyInfo.Name;
            this.Info = propertyInfo;
        }


        /// <summary>
        /// 属性赋值操做(Emit技术)
        /// </summary>
        /// <param name="instance"></param>
        /// <param name="value"></param>
        public void SetValue(Object instance,Object value)
        {
            this.setter?.Invoke(instance, value);
        }

        /// <summary>
        /// 属性取值操做(Emit技术)
        /// </summary>
        /// <param name="instance"></param>
        /// <returns></returns>
        public Object GetValue(Object instance)
        {
            return this.getter?.Invoke(instance);
        }

        private static readonly ConcurrentDictionary<Type, PropertyEmit[]> securityCache = new ConcurrentDictionary<Type, PropertyEmit[]>();

        /// <summary>
        /// 获取对象属性
        /// </summary>
        /// <param name="type">对象类型</param>
        /// <returns></returns>
        public static PropertyEmit[] GetProperties(Type type)
        {
            return securityCache.GetOrAdd(type, t => t.GetProperties().Select(p => new PropertyEmit(p)).ToArray());
        }
    }

    /// <summary>
    /// Emit 动态构造 Get方法
    /// </summary>
    public  class PropertyGetterEmit
    {

        private readonly Func<Object, Object> getter;
        public PropertyGetterEmit(PropertyInfo propertyInfo)
        {
            //Objcet value = Obj.GetValue(Object instance);
            if (propertyInfo == null)
            {
                throw new ArgumentNullException("propertyInfo");
            }
            this.getter = CreateGetterEmit(propertyInfo);

        }

        public Object Invoke(Object instance)
        {
            return getter?.Invoke(instance);
        }

        private Func<Object, Object> CreateGetterEmit(PropertyInfo property)
        {
            if (property == null)
                throw new ArgumentNullException("property");

            MethodInfo getMethod = property.GetGetMethod(true);

            DynamicMethod dm = new DynamicMethod("PropertyGetter", typeof(Object),
                new Type[] { typeof(Object) },
                property.DeclaringType, true);

            ILGenerator il = dm.GetILGenerator();

            if (!getMethod.IsStatic)
            {
                il.Emit(OpCodes.Ldarg_0);
                il.EmitCall(OpCodes.Callvirt, getMethod, null);
            }
            else
                il.EmitCall(OpCodes.Call, getMethod, null);

            if (property.PropertyType.IsValueType)
                il.Emit(OpCodes.Box, property.PropertyType);
            il.Emit(OpCodes.Ret);
            return (Func<Object, Object>)dm.CreateDelegate(typeof(Func<Object, Object>));
        }
    }

    /// <summary>
    /// Emit动态构造Set方法
    /// </summary>
    public class PropertySetterEmit
    {
        private readonly Action<Object, Object> setFunc;
        public PropertySetterEmit(PropertyInfo propertyInfo)
        {
            //Obj.Set(Object instance,Object value)
            if (propertyInfo == null)
            {
                throw new ArgumentNullException("propertyInfo");
            }
            this.setFunc = CreatePropertySetter(propertyInfo);

        }

        private Action<Object, Object> CreatePropertySetter(PropertyInfo property)
        {
            if (property == null)
                throw new ArgumentNullException("property");

            MethodInfo setMethod = property.GetSetMethod(true);

            DynamicMethod dm = new DynamicMethod("PropertySetter", null,
                new Type[] { typeof(Object), typeof(Object) }, property.DeclaringType, true);

            ILGenerator il = dm.GetILGenerator();

            if (!setMethod.IsStatic)
            {
                il.Emit(OpCodes.Ldarg_0);
            }
            il.Emit(OpCodes.Ldarg_1);

            EmitCastToReference(il, property.PropertyType);
            if (!setMethod.IsStatic && !property.DeclaringType.IsValueType)
            {
                il.EmitCall(OpCodes.Callvirt, setMethod, null);
            }
            else
                il.EmitCall(OpCodes.Call, setMethod, null);

            il.Emit(OpCodes.Ret);
            return (Action<Object, Object>)dm.CreateDelegate(typeof(Action<Object, Object>));
        }

        private static void EmitCastToReference(ILGenerator il, Type type)
        {
            if (type.IsValueType)
                il.Emit(OpCodes.Unbox_Any, type);
            else
                il.Emit(OpCodes.Castclass, type);
        }

        public void Invoke(Object instance,Object value)
        {
            this.setFunc?.Invoke(instance, value);
        }
    }

 

  与表达式一块儿对比,其测试代码以下:工具

 

            Student student = new Student(); //学生对象,里面有一个Name属性
            PropertyInfo propertyInfo = student.GetType().GetProperty(nameof(student.Name));
            Property PropertyExp = new Property(propertyInfo);
            PropertyEmit propertyEmit = new PropertyEmit(propertyInfo);

            Int32 loopCount = 1000000;  //执行次数
            CodeTimer.Initialize();  //测试环境初始化


            CodeTimer.Time("基础反射", loopCount, () => { 
                propertyInfo.SetValue(student, "Fode",null);
            });
            CodeTimer.Time("lambda表达式树", loopCount, () => {
                PropertyExp.SetValue(student, "Fode");
            });
            CodeTimer.Time("Emit",loopCount,()=> {
                propertyEmit.SetValue(student, "Fode");
            });
            CodeTimer.Time("直接赋值", loopCount, () => {
                student.Name = "Fode";
            });
            Console.ReadKey();

测试效果图以下:表达式与Emit速度基本相同,将我上述的方法CreatePropertySetter改为静态会比表达式快一点。在使用的过程当中,最好将其封装成一个静态泛型类缓存起来,一直new PropertyEmit这个对象反而效率会很低。代码下载oop

  

文章结尾在分享几个我认为写得不错,可能对你们有帮助的文章:post

C# 之 反射性能优化1

Emit经常使用Opcodes指令使用方法(含实例)

从IDataReader中读取数据实体性能

相关文章
相关标签/搜索