程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 顛覆常識??Reflection、Delegate、Expression 生成實體類,實測結果,反射最快。

顛覆常識??Reflection、Delegate、Expression 生成實體類,實測結果,反射最快。

編輯:C#入門知識

我的ORM一直是用反射來實現動態生成Entity的,最近想提高一下效率,就嘗試了一下用其他的方法來生成實體類。平時看到的資料都說用Expression的速度已經接近於Emit了,效率非常高,但測試的結果卻讓我大跌眼鏡。。。下面對直接賦值、反射、委托、Expression四種方式來生成實體類進行測試。(暫時不考慮Emit),如果大家有其他更好的方法來生成實體類,請不吝賜教,謝謝。
先上測試結果:(環境: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...

從結果中可以,直接賦值最快(但寫和維護太麻煩,實際項目中一般不考慮),然後就是反射,到了用Expression的方式,效率是數量級的下降啊,比反射慢幾十倍?
不知道是不是我的測試用例寫的問題,下面詳細說明一下我的測試過程:
1、原始數據是一個DataTable, 只有一行數據,三列。分別為Name,Age,Sex ,下面所有的轉化只是把DataTable的第一行轉為一個實體類。
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、要生成的實體類也很簡單,只有三個property,為了避免類型轉換等問題,用最簡單的,都是string 類型。
public class Customer
    {
        public string Name { get; set; }
        public string Age { get; set; }
        public string Sex { get; set; }
    }


3、直接賦值的方法:
 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、反射生成實體類的方法:
 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、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、主程序:
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();
        }

 

這只一個用最簡單的實例來測試,我在本地用數據庫中的5萬條數據,表中20幾個Column的實際數據測試,結果差別更大。
因個人水平有限,測試做的簡陋,如果有不當的地方,請大家指出。


完整測試代碼下載:https://docs.google.com/open?id=0B9pEVL9Vjb34dGFUX0RWQnZSd1dsd0d3MXRWZ29RQQ ,點擊File菜單中的Download即可。

 

摘自  天羽
 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved