用DynamicMethod提升ORM系统转换业务数据的性能
在上一篇文章《把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();
}
}
原贴地址:http://www.cnblogs.com/yahong111/archive/2007/08/07/845571.html