問題根源:現在編碼已經習慣了面向對象編碼,數據庫訪問層也由ORM代替了ADO,DataTable一般用的越來越少,可是一些公用方法還是用到DataTable了,理由其實很簡單就是公用方法里不用DataTable就得用反射訪問實體集合,反射的訪問效率比DataTable低很多是毋庸置疑的。可是我還是覺得很苦惱,心中有兩個疑問:
1、訪問實體集合到底比訪問DataTable慢多少呢?
2、后台數據層提供的是實體集合,調用公用方法勢必要轉為DataTable,那轉換耗時多少呢?
接下來我新建了一個控制台程序,簡單寫了一個實體對象:

1 public class TestEntity 2 { 3 public string Col1 { get; set; } 4 public string Col2 { get; set; } 5 public string Col3 { get; set; } 6 public string Col4 { get; set; } 7 public string Col5 { get; set; } 8 public string Col6 { get; set; } 9 public string Col7 { get; set; } 10 public string Col8 { get; set; } 11 public string Col9 { get; set; } 12 public string Col10 { get; set; } 13 public string Col11 { get; set; } 14 public string Col12 { get; set; } 15 public string Col13 { get; set; } 16 public string Col14 { get; set; } 17 public string Col15 { get; set; } 18 public string Col16 { get; set; } 19 public string Col17 { get; set; } 20 public string Col18 { get; set; } 21 public string Col19 { get; set; } 22 public string Col20 { get; set; } 23 public string Col21 { get; set; } 24 public string Col22 { get; set; } 25 public string Col23 { get; set; } 26 public string Col24 { get; set; } 27 public string Col25 { get; set; } 28 public string Col26 { get; set; } 29 public string Col27 { get; set; } 30 public string Col28 { get; set; } 31 public string Col29 { get; set; } 32 public string Col30 { get; set; } 33 }
然后寫了一個創建實體集合的方法:

1 private static IList<TestEntity> CreateList(long count) 2 { 3 var result = new List<TestEntity>(); 4 5 for (var i = 0; i < count; i++) 6 { 7 var entity = new TestEntity(); 8 var propertys = typeof(TestEntity).GetProperties(); 9 foreach (var p in propertys) 10 { 11 p.SetValue(entity, i.ToString()); 12 } 13 result.Add(entity); 14 } 15 16 return result; 17 }
然后寫了一個創建DataTable的方法:

1 private static DataTable CreateTable(long count) 2 { 3 var result = new DataTable(); 4 5 for (var i = 1; i <= 30; i++) 6 { 7 result.Columns.Add(new DataColumn("Col" + i.ToString(), Type.GetType("System.String"))); 8 } 9 10 for (var i = 0; i < count; i++) 11 { 12 var row = result.NewRow(); 13 for (var j = 1; j <= 30; j++) 14 { 15 row["Col" + j.ToString()] = i; 16 } 17 result.Rows.Add(row); 18 } 19 20 return result; 21 }
准備工作做好了,現在寫了兩個讀取的方法:

1 private static void ReadEntity<T>(IList<T> list) 2 { 3 for (var i = 0; i < list.Count; i++) 4 { 5 var entity = list[i]; 6 var propertys = typeof(T).GetProperties(); 7 for (var j = 0; j < propertys.Count(); j++) 8 { 9 var value = ""; 10 value += propertys[j].GetValue(entity).ToString(); 11 } 12 } 13 }

1 private static void ReadDataTable(DataTable data) 2 { 3 for (var i = 0; i < data.Rows.Count; i++) 4 { 5 for (var j = 0; j < data.Columns.Count; j++) 6 { 7 var value = ""; 8 value += data.Rows[i][j].ToString(); 9 } 10 } 11 }
記錄一下耗時,通過控制台打印出來:

1 static void Main(string[] args) 2 { 3 for (var i = 0; i < 10; i++) 4 { 5 var count = Convert.ToInt64(Console.ReadLine()); 6 if (count == 0) break; 7 8 var list = CreateList(count); 9 10 11 DateTime start = DateTime.Now; 12 var table = CreateTable(count); 13 DateTime end = DateTime.Now; 14 15 var tick0 = (end - start).Ticks; 16 17 start = DateTime.Now; 18 ReadDataTable(table); 19 end = DateTime.Now; 20 21 var tick1 = (end - start).Ticks; 22 23 start = DateTime.Now; 24 ReadEntity(list); 25 end = DateTime.Now; 26 27 var tick2 = (end - start).Ticks; 28 29 Console.WriteLine("DataTable:條數" + count + "耗時" + tick1.ToString()); 30 Console.WriteLine("反射讀取Entity:條數" + count + "耗時" + tick2.ToString()); 31 } 32 }
運行程序,輸入行數,顯示結果如下:
可以看出反射讀取耗時與DataTable讀取耗時相比2到4倍。
這時你肯定會想差這么多,看來公用方法使用DataTable是沒錯了。
但是,開頭咱們提到的兩個疑問,第一個疑問解決了,但是第二個疑問呢,轉換耗時多少呢?
現在我把第二個疑問拆解了一下,轉換需要進行的是,創建DataTable,遍歷讀取實體集合(注意一下這個不是反射),這樣我就寫了一個方法:

1 private static DataTable CreateTable(IList<TestEntity> list) 2 { 3 var result = new DataTable(); 4 5 for (var i = 1; i <= 30; i++) 6 { 7 result.Columns.Add(new DataColumn("Col" + i.ToString(), Type.GetType("System.String"))); 8 } 9 10 for (var i = 0; i < list.Count; i++) 11 { 12 var row = result.NewRow(); 13 row["Col1"] = list[i].Col1; 14 row["Col2"] = list[i].Col2; 15 row["Col3"] = list[i].Col3; 16 row["Col4"] = list[i].Col4; 17 row["Col5"] = list[i].Col5; 18 row["Col6"] = list[i].Col6; 19 row["Col7"] = list[i].Col7; 20 row["Col8"] = list[i].Col8; 21 row["Col9"] = list[i].Col9; 22 row["Col10"] = list[i].Col10; 23 row["Col11"] = list[i].Col11; 24 row["Col12"] = list[i].Col12; 25 row["Col13"] = list[i].Col13; 26 row["Col14"] = list[i].Col14; 27 row["Col15"] = list[i].Col15; 28 row["Col16"] = list[i].Col16; 29 row["Col17"] = list[i].Col17; 30 row["Col18"] = list[i].Col18; 31 row["Col19"] = list[i].Col19; 32 row["Col20"] = list[i].Col20; 33 row["Col21"] = list[i].Col21; 34 row["Col22"] = list[i].Col22; 35 row["Col23"] = list[i].Col23; 36 row["Col24"] = list[i].Col24; 37 row["Col25"] = list[i].Col25; 38 row["Col26"] = list[i].Col26; 39 row["Col27"] = list[i].Col27; 40 row["Col28"] = list[i].Col28; 41 row["Col29"] = list[i].Col29; 42 row["Col30"] = list[i].Col30; 43 result.Rows.Add(row); 44 } 45 46 return result; 47 }
在主函數增加時間記錄:

1 start = DateTime.Now; 2 CreateTable(list); 3 end = DateTime.Now; 4 5 var tick3 = (end - start).Ticks; 6 Console.WriteLine("Entity:條數" + count + "耗時" + tick3.ToString());
執行結果如下:
創建DataTable加上讀取與通過反射直接讀取實體集合,耗時相差不是很明顯了,起碼不是倍率級的了,在大環境下,我個人覺得考慮到維護性和開發效率,我推薦直接使用反射寫公用方法。