My ORM has been using reflection to dynamically generate Entity. Recently I tried other methods to generate Entity classes to improve efficiency. The materials we usually see show that the Expression speed is close to that of Emit, and the efficiency is very high, but the test results have surprised me... The following describes how to generate an object class using direct assignment, reflection, delegation, and Expression. (Do not consider Emit for the time being.) If you have other better methods to generate entity classes, please kindly advise. Thank you.
Test result: (Environment: Windows 7 64 bit, I7 950,12G ram, VS2010)
Assign, generate entity 10000 times, time: 2
Reflection, generate entity 10000 times, time: 54
Delegate, generate entity 10000 times, time: 134
Expression, generate entity 10000 times, time: 4323
Press any key to continue...
From the results, you can directly assign values as quickly as possible (but writing and maintenance are too troublesome, which is generally not considered in the actual project), then reflection is used, and Expression is used, efficiency is reduced by an order of magnitude. How many times slower than reflection?
I don't know if it is my test case writing problem. The following describes my test process in detail:
1. The raw data is a DataTable with only one row of data and three columns. They are Name, Age, and Sex respectively. All the conversions below convert the first row of the able into an object class.
Public static DataTable GetCustomer ()
{
DataTable dt = new DataTable ();
Dt. Columns. Add (new DataColumn ("Name", typeof (System. String )));
Dt. Columns. Add (new DataColumn ("Age", typeof (System. String )));
Dt. Columns. Add (new DataColumn ("Sex", typeof (System. String )));
DataRow dr = dt. NewRow ();
Dr ["Name"] = "Andy ";
Dr ["Age"] = "33 ";
Dr ["Sex"] = "Male ";
Dt. Rows. Add (dr );
Return dt;
}
2. The entity class to be generated is also very simple. There are only three properties. To avoid type conversion and other problems, the simplest method is to use the string type.
Public class Customer
{
Public string Name {get; set ;}
Public string Age {get; set ;}
Public string Sex {get; set ;}
}
3. Direct assignment:
1 public class ToEntityByAssign
2 {
3 public Customer GetEntity (DataTable dt)
4 {
5 DataRow dr = dt. Rows [0];
6 Customer cus = new Customer ();
7 cus. Name = dr ["Name"]. ToString ();
8 cus. Age = dr ["Age"]. ToString ();
9 cus. Sex = dr ["Sex"]. ToString ();
10 return cus;
11}
12}
4. Reflection:
1 public class ToEntityByReflection <T>
2 {
3 public T GetEntity (DataTable dt)
4 {
5 Type type = typeof (T );
6 T model = (T) Activator. CreateInstance (typeof (T ));
7 DataRow dr = dt. Rows [0];
8
9 foreach (PropertyInfo pi in type. GetProperties ())
10 {
11 pi. SetValue (model, Convert. ChangeType (dr [pi. Name], pi. PropertyType), null );
12}
13
14 return model;
15}
16}
5. Delegate:
1 public delegate void SetString (string value );
2 public class ToEntityByDelegate <T>
3 {
4 public T GetEntity (DataTable dt)
5 {
6 Type type = typeof (T );
7 T model = (T) Activator. CreateInstance (typeof (T ));
8 DataRow dr = dt. Rows [0];
9
10 foreach (DataColumn dc in dt. Columns)
11 {
12 var setDelegateString = CreateStringDelegate (model, dc. ColumnName );
13 setDelegateString (dr [dc. ColumnName]. ToString ());
14}
15 return model;
16}
17
18 private static SetString CreateStringDelegate (object obj, string PropertyName)
19 {
20 MethodInfo mi = obj. GetType (). GetProperty (PropertyName). GetSetMethod ();
21 Type type = typeof (SetString );
22 return (SetString) Delegate. CreateDelegate (type, obj, mi );
23}
24}
6. How to generate an object using Expression:
Public static class ToEntityByExpression
{
Public static T GetEntity <T> (DataTable dt)
{
T t = (T) Activator. CreateInstance (typeof (T ));
DataRow dr = dt. Rows [0];
Foreach (PropertyInfo p in typeof (T). GetProperties ())
{
Object value = dr [p. Name] = DBNull. Value? Null: dr [p. Name];
P. FastSetValue <T> (t, value );
}
Return t;
}
Static Func <T, object, object> GetSetDelegate <T> (MethodInfo m, Type type)
{
ParameterExpression param_obj = Expression. Parameter (typeof (T), "obj ");
ParameterExpression param_val = Expression. Parameter (typeof (object), "val ");
UnaryExpression body_val = Expression. Convert (param_val, type );
MethodCallExpression body = Expression. Call (param_obj, m, body_val );
Action <T, object> set = Expression. Lambda <Action <T, object> (body, param_obj, param_val). Compile ();
Return (instance, v) =>
{
Set (instance, v );
Return null;
};
}
Static void FastSetValue <T> (this PropertyInfo property, T t, object value)
{
MethodInfo m = property. GetSetMethod ();
GetSetDelegate <T> (m, property. PropertyType) (t, value );
}
}
7. Main Program:
Static void Main (string [] args)
{
Stopwatch sw = new Stopwatch ();
DataTable dt = DataTableData. GetCustomer ();
Int times = 10000;
Sw. Restart ();
For (int I = 0; I <times; I ++)
{
Customer cusReflection = new ToEntityByAssign (). GetEntity (dt );
}
Sw. Stop ();
Console. writeLine ("{0}, generate entity {1} times, time: {2}", "Assign ". padRight (12, ''), times, sw. elapsedMilliseconds. toString ());
Sw. Restart ();
For (int I = 0; I <times; I ++)
{
Customer cusReflection = new ToEntityByReflection <Customer> (). GetEntity (dt );
}
Sw. Stop ();
Console. writeLine ("{0}, generate entity {1} times, time: {2}", "Reflection ". padRight (12, ''), times, sw. elapsedMilliseconds. toString ());
Sw. Restart ();
For (int I = 0; I <times; I ++)
{
Customer cusDelegate = new ToEntityByDelegate <Customer> (). GetEntity (dt );
}
Sw. Stop ();
Console. writeLine ("{0}, generate entity {1} times, time: {2}", "Delegate ". padRight (12, ''), times, sw. elapsedMilliseconds. toString ());
Sw. Restart ();
For (int I = 0; I <times; I ++)
{
Customer cusExpress = ToEntityByExpression. GetEntity <Customer> (dt );
}
Sw. Stop ();
Console. writeLine ("{0}, generate entity {1} times, time: {2}", "Expression ". padRight (12, ''), times, sw. elapsedMilliseconds. toString ());
Console. WriteLine ();
Console. WriteLine ("Press any key to continue ...");
Console. ReadKey ();
}
This is a test using the simplest instance. I use 50 thousand pieces of data in the local database. The actual data of the 20 columns in the table is tested, and the results are more different.
Due to the limited individual level, the test is simple. If there is anything inappropriate, please point it out.
Full test code download: https://docs.google.com/open? Id = 0B9pEVL9Vjb34dGFUX0RWQnZSd1dsd0d3MXRWZ29RQQ. Click Download In the File menu.
From Tian Yu