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

本文介绍使用DynamicMethod来提高ORM系统将SQL数据转换为业务数据的效率。此方法不仅简化了业务实体类的设计,还能在运行时达到接近硬编码的速度,并且能够灵活地对不同的业务实体类进行转换。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在上一篇文章《Sql数据转换为业务数据的几种方法》中提到了ORM系统把Sql数据转换为业务数据的几种方法,但这些方法都不是最佳的方法,后有白菜园等朋友提出用DynamicMethod,发现该方法确实是一个理想的解决方案:
1、在设计的时候业务实体类的定义非常简洁;
2、在运行的时候效率比较高,在某些情况下,甚至与硬编码的效率相等。
3、解偶了数据转换类和业务实体类之间的关系,可以对任意的业务实体类进行转换而不用对他们进行修改。
 
经过简单测试,发现用DynamicMethod的时间大约是硬编码的1~1.2倍,而用反射所花的时间大约是硬编码和DynamicMethod的4~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();
        }
}
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值