(转)用DynamicMethod提升ORM系统转换业务数据的性能

在上一篇文章《Sql数据转换为业务数据的几种方法》中提到了ORM系统把Sql数据转换为业务数据的几种方法,但这些方法都不是最佳的方法,后有白菜园等朋友提出用DynamicMethod,发现该方法确实是一个理想的解决方案:

1、在设计的时候业务实体类的定义非常简洁;

2、在运行的时候效率比较高,在某些情况下,甚至与硬编码的效率相等。

3、解偶了数据转换类和业务实体类之间的关系,可以对任意的业务实体类进行转换而不用对他们进行修改。

经过简单测试,发现用DynamicMethod的时间大约是硬编码的1~1.2倍,而用反射所花的时间大约是硬编码和DynamicMethod4~6.5倍。现与大家分享代码,期待能够找到更加好的方法。

业务实体类User,对应着数据库的Users表:

public class User

     {

        string _UserID;

       public string UserID

        {

            get { return _UserID; }

            set { _UserID = value; }

        }

 

        string _UserName;

        public string UserName

        {

            get { return _UserName; }

            set { _UserName = value; }

        }

 

        string _Email;

        public string Email

        {

            get { return _Email; }

            set { _Email = value; }

        }

 

        string _Pwd;

        public string Pwd

        {

            get { return _Pwd; }

            set { _Pwd = value; }

        }

}

用于执行DynamicMethod的委托:

public delegate T FillBusinessObject<T>(IDataReader AReader);

创建DynamicMethod

public class BusinessSetter

    {

        static string[] GetFields(string tableName)

        {

            return new String[] { "UserID", "UserName", "Email", "Pwd" };

        }

        public static FillBusinessObject<T> GetFillMethod<T>(string tableName) where T : new()

        {

            Type AType = typeof(T);

            Type[] methodArgs ={ typeof(IDataReader) };

            DynamicMethod AFillMethod = new DynamicMethod("", AType, methodArgs, AType);

            ILGenerator il = AFillMethod.GetILGenerator();

            MethodInfo DataReaderGet = typeof(SqlDataReader).GetMethod("get_Item", new Type[] { typeof(string) });                       

            ConstructorInfo createInfo = AType.GetConstructor(new Type[0]);

            il.DeclareLocal(AType);           

            il.Emit(OpCodes.Newobj, createInfo);

            il.Emit(OpCodes.Stloc_0);

            string[] Fields = GetFields(tableName);

            foreach (string AFieldName in Fields)

            {

                PropertyInfo AProp = AType.GetProperty(AFieldName);

                MethodInfo PropSetMethod = AProp.GetSetMethod();

 

                il.Emit(OpCodes.Ldloc_0);

                il.Emit(OpCodes.Ldarg_0);

                il.Emit(OpCodes.Ldstr, AFieldName);

                il.Emit(OpCodes.Callvirt, DataReaderGet);

                il.Emit(OpCodes.Isinst, AProp.PropertyType);

             

                il.Emit(OpCodes.Callvirt, PropSetMethod);

            }

            il.Emit(OpCodes.Ldloc_0);

            il.Emit(OpCodes.Ret);

 

            return (FillBusinessObject<T>)AFillMethod.CreateDelegate(typeof(FillBusinessObject<T>));

        }    

 }

测试:

public class Test

    {

        public static void Main()

        {           

            FillBusinessObject<User> AMethod = BusinessSetter.GetFillMethod<User>("Users");

 

            string Sql = "select UserID,UserName,Pwd,Email from Users";

            SqlConnection con = new SqlConnection(System.Configuration.ConfigurationManager.AppSettings["DbCon"]);

            SqlCommand cmd = new SqlCommand(Sql, con);

            con.Open();

 

            for (int i = 0; i < 5; i++)

            {

                //DynamicMethod

                Console.WriteLine("{0}th time:",i+1);

                SqlDataReader reader = cmd.ExecuteReader();

                long dynamic = 0;

                long start = DateTime.Now.Ticks;

                while (reader.Read())

                {                   

                    User AUser=AMethod(reader);                   

                }               

                long end = DateTime.Now.Ticks;

                reader.Close();

                dynamic = end - start;

                Console.WriteLine("dynamic:{0}", dynamic);               

                             

                // Hardcode

                reader = cmd.ExecuteReader();

                start = DateTime.Now.Ticks;

                while (reader.Read())

                {

                    User AUser = new User();

                    AUser.UserName = reader["UserName"] as string;

                    AUser.Email = reader["Email"] as string;

                    AUser.UserID = reader["UserID"] as string;

                    AUser.Pwd = reader["Pwd"] as string;

                }

                end = DateTime.Now.Ticks;

                reader.Close();               

                long hardcode = end - start;

                Console.WriteLine("hardcode:{0}", hardcode);               

 

                //Reflect

                reader = cmd.ExecuteReader();               

                Type UserType=typeof(User);

                PropertyInfo[] UserInfos ={

                    UserType.GetProperty("UserID"),

                    UserType.GetProperty("UserName"),

                    UserType.GetProperty("Pwd"),

                    UserType.GetProperty("Email")};

 

                start = DateTime.Now.Ticks;

                while (reader.Read())

                {

                    User AUser = new User();

                    foreach (PropertyInfo info in UserInfos)

                        info.SetValue(AUser, reader[info.Name], null);

                }               

                end = DateTime.Now.Ticks;

                reader.Close();

                long reflect = end - start;

                Console.WriteLine("reflect:{0}", reflect);

 

                Console.WriteLine("dynamic/hardcode={0}", (float)dynamic / (float)hardcode);

                Console.WriteLine("reflect/hardcode={0}", (float)reflect / (float)hardcode);

                Console.WriteLine("reflect/dynamic={0}", (float)reflect / (float)dynamic);

 

                Console.WriteLine();

                Thread.Sleep(50);

            }

            con.Close();

            Console.Read();

        }

}

原文地址:https://www.cnblogs.com/gxh973121/p/847770.html