十年網(wǎng)站開(kāi)發(fā)經(jīng)驗(yàn) + 多家企業(yè)客戶 + 靠譜的建站團(tuán)隊(duì)
量身定制 + 運(yùn)營(yíng)維護(hù)+專業(yè)推廣+無(wú)憂售后,網(wǎng)站問(wèn)題一站解決
因?yàn)長(zhǎng)inq的查詢功能很強(qiáng)大,所以從數(shù)據(jù)庫(kù)中拿到的數(shù)據(jù)為了處理方便,我都會(huì)轉(zhuǎn)換成實(shí)體集合List
文昌網(wǎng)站制作公司哪家好,找創(chuàng)新互聯(lián)公司!從網(wǎng)頁(yè)設(shè)計(jì)、網(wǎng)站建設(shè)、微信開(kāi)發(fā)、APP開(kāi)發(fā)、響應(yīng)式網(wǎng)站建設(shè)等網(wǎng)站項(xiàng)目制作,到程序開(kāi)發(fā),運(yùn)營(yíng)維護(hù)。創(chuàng)新互聯(lián)公司于2013年開(kāi)始到現(xiàn)在10年的時(shí)間,我們擁有了豐富的建站經(jīng)驗(yàn)和運(yùn)維經(jīng)驗(yàn),來(lái)保證我們的工作的順利進(jìn)行。專注于網(wǎng)站建設(shè)就選創(chuàng)新互聯(lián)公司。
開(kāi)始用的是硬編碼的方式,好理解,但通用性極低,下面是控件臺(tái)中的代碼:
1 using System; 2 using System.Collections.Generic; 3 using System.Data; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 7 8 namespace Demo1 9 {10 class Program11 {12 static void Main(string[] args)13 {14 DataTable dt = Query();15 Listusrs = new List (dt.Rows.Count);16 //硬編碼,效率比較高,但靈活性不夠,如果實(shí)體改變了,都需要修改代碼17 foreach (DataRow dr in dt.Rows)18 {19 Usr usr = new Usr { ID = dr.Field ("ID"), Name = dr.Field ("Name") };20 usrs.Add(usr);21 }22 usrs.Clear();23 }24 25 /// 26 /// 查詢數(shù)據(jù)27 /// 28 ///29 private static DataTable Query()30 {31 DataTable dt = new DataTable();32 dt.Columns.Add("ID", typeof(Int32));33 dt.Columns.Add("Name", typeof(String));34 for (int i = 0; i < 1000000; i++)35 {36 dt.Rows.Add(new Object[] { i, Guid.NewGuid().ToString() });37 }38 return dt;39 }40 }41 class Usr42 {43 public Int32? ID { get; set; }44 public String Name { get; set; }45 }46 }
后來(lái)用反射來(lái)做這,對(duì)實(shí)體的屬性用反射去賦值,這樣就可以對(duì)所有的實(shí)體通用,且增加屬性后不用修改代碼。
程序如下:
1 static class EntityConvert 2 { 3 ///4 /// DataTable轉(zhuǎn)為L(zhǎng)ist 6 ///5 /// 7 /// 8 /// 9 public static List ToList (this DataTable dt) where T : class, new()10 {11 List colletion = new List ();12 PropertyInfo[] pInfos = typeof(T).GetProperties();13 foreach (DataRow dr in dt.Rows)14 {15 T t = new T();16 foreach (PropertyInfo pInfo in pInfos)17 {18 if (!pInfo.CanWrite) continue;19 pInfo.SetValue(t, dr[pInfo.Name]);20 }21 colletion.Add(t);22 }23 return colletion;24 }25 }
增加一個(gè)擴(kuò)展方法,程序更加通用。但效率不怎么樣,100萬(wàn)行數(shù)據(jù)【只有兩列】,轉(zhuǎn)換需要2秒
后來(lái)想到用委托去做 委托原型如下
1 Funcfunc = dr => new Usr { ID = dr.Field ("ID"), Name = dr.Field ("Name") };
代碼如下:
1 static void Main(string[] args) 2 { 3 DataTable dt = Query(); 4 Funcfunc = dr => new Usr { ID = dr.Field ("ID"), Name = dr.Field ("Name") }; 5 List usrs = new List (dt.Rows.Count); 6 Stopwatch sw = Stopwatch.StartNew(); 7 foreach (DataRow dr in dt.Rows) 8 { 9 Usr usr = func(dr);10 usrs.Add(usr);11 }12 sw.Stop();13 Console.WriteLine(sw.ElapsedMilliseconds);14 usrs.Clear();15 Console.ReadKey();16 }
速度確實(shí)快了很多,我電腦測(cè)試了一下,需要 0.4秒。但問(wèn)題又來(lái)了,這個(gè)只能用于Usr這個(gè)類,得想辦法把這個(gè)類抽象成泛型T,既有委托的高效,又有
泛型的通用。
問(wèn)題就在動(dòng)態(tài)地產(chǎn)生上面的委托了,經(jīng)過(guò)一下午的折騰終于折騰出來(lái)了動(dòng)態(tài)產(chǎn)生委托的方法。主要用到了動(dòng)態(tài)Lambda表達(dá)式
1 public static class EntityConverter 2 { 3 ///4 /// DataTable生成實(shí)體 5 /// 6 ///7 /// 8 /// 9 public static List ToList (this DataTable dataTable) where T : class, new()10 {11 if (dataTable == null || dataTable.Rows.Count <= 0) throw new ArgumentNullException("dataTable", "當(dāng)前對(duì)象為null無(wú)法生成表達(dá)式樹(shù)");12 Func func = dataTable.Rows[0].ToExpression ();13 List collection = new List (dataTable.Rows.Count);14 foreach (DataRow dr in dataTable.Rows)15 {16 collection.Add(func(dr));17 }18 return collection;19 }20 21 /// 22 /// 生成表達(dá)式23 /// 24 ///25 /// 26 /// 27 public static Func ToExpression (this DataRow dataRow) where T : class, new()28 {29 if (dataRow == null) throw new ArgumentNullException("dataRow", "當(dāng)前對(duì)象為null 無(wú)法轉(zhuǎn)換成實(shí)體");30 ParameterExpression paramter = Expression.Parameter(typeof(DataRow), "dr");31 List binds = new List ();32 for (int i = 0; i < dataRow.ItemArray.Length; i++)33 {34 String colName = dataRow.Table.Columns[i].ColumnName;35 PropertyInfo pInfo = typeof(T).GetProperty(colName);36 if (pInfo == null) continue;37 MethodInfo mInfo = typeof(DataRowExtensions).GetMethod("Field", new Type[] { typeof(DataRow), typeof(String) }).MakeGenericMethod(pInfo.PropertyType);38 MethodCallExpression call = Expression.Call(mInfo, paramter, Expression.Constant(colName, typeof(String)));39 MemberAssignment bind = Expression.Bind(pInfo, call);40 binds.Add(bind);41 }42 MemberInitExpression init = Expression.MemberInit(Expression.New(typeof(T)), binds.ToArray());43 return Expression.Lambda >(init, paramter).Compile();44 }45 }
經(jīng)過(guò)測(cè)試,用這個(gè)方法在同樣的條件下轉(zhuǎn)換實(shí)體需要 0.47秒。除了第一次用反射生成Lambda表達(dá)式外,后續(xù)的轉(zhuǎn)換直接用的表達(dá)式。