C#中DataTable与泛型集合互转(支持泛型集合中对象包含枚举)

最近在做WCF,因为是内部接口,很多地方直接用的弱类型返回(DataSet),这其实是一种非常不好的方式,最近将项目做了修改,将所有接口返回值都修改成强类型,这样可以减少很多与客户端开发人员的沟通,结构内容一目了然

很多时候,后台我们通过ADO.NET使用SQL语句查询出了想要的数据,这时如果直接把这个DataSet丢给客户端开发人员,会让他们一头雾水,并且维护扩展起来都很麻烦,所以想了一个办法,在服务端,首先我们把查询到的数据集转换成泛型集合,再返回给客户端,客户端可以直接使用,也可以再自行转换成自己需要的数据格式,这样做还有一点是因为,DataTable在进行序列化与反序列化时并不那么可靠,记得在多线程同时序列化一个DataTable时会有异常,另外也隐藏了很多小问题,例如需要序列化DataTable的话必须设置TableName等等

首先是封装的辅助类,这个辅助类还可以完善,因为我这里数据库数据类型与实体对象的类型可以直接转换,如果实体类类型与数据库内类型不同,则需要做相应的转换

  1 static class Helper
  2     {
  3         /// <summary> 
  4         ///  DataTable转换成泛型集合
  5         /// </summary> 
  6         /// <typeparam name="T">泛型集合类型</typeparam> 
  7         /// <param name="dt">DataTable</param> 
  8         /// <param name="dEnum">字典集合,Key为需要从转换为enum项的DataColumnName,Value为需要转换的枚举的类型</param> 
  9         /// <returns>以实体类为元素的泛型集合</returns> 
 10         public static IList<T> DataTableConvertToListGenuric<T>(DataTable dt, Dictionary<string, Type> dEnum) where T : new()
 11         {
 12             if (dt?.Rows.Count > 0)
 13             {
 14                 // 定义集合 
 15                 List<T> ts = new List<T>();
 16                 // 获得此模型的类型 
 17                 Type type = typeof(T);
 18                 //定义一个临时变量 
 19                 string tempName = string.Empty;
 20                 //遍历DataTable中所有的数据行  
 21                 foreach (DataRow dr in dt.Rows)
 22                 {
 23                     T t = new T();
 24                     //如果T是值类型,则先进行装箱
 25                     object obj = null;
 26                     if (!t.GetType().IsClass)
 27                     {
 28                         obj = t;
 29                     }
 30                     //获得此模型的公共属性 
 31                     PropertyInfo[] propertys = t.GetType().GetProperties();
 32                     //遍历该对象的所有属性 
 33                     foreach (PropertyInfo pi in propertys)
 34                     {
 35                         //将属性名称赋值给临时变量   
 36                         tempName = pi.Name;
 37                         //检查DataTable是否包含此列(列名==对象的属性名)     
 38                         if (dt.Columns.Contains(tempName))
 39                         {
 40                             // 判断此属性是否有Setter   
 41                             if (!pi.CanWrite) continue;//该属性不可写,直接跳出   
 42                             //取值   
 43                             object value = dr[tempName];
 44                             //如果非空,则赋给对象的属性   
 45                             if (value != DBNull.Value)
 46                             {
 47                                 //如果有枚举项
 48                                 if (dEnum != null)
 49                                 {
 50                                     var queryResult = from n in dEnum
 51                                                       where n.Key == tempName
 52                                                       select n;
 53                                     //枚举集合中包含与当前属性名相同的项
 54                                     if (queryResult.Count() > 0)
 55                                     {
 56                                         if (obj != null)
 57                                         {
 58                                             //将字符串转换为枚举对象
 59                                             pi.SetValue(obj, Enum.Parse(queryResult.FirstOrDefault().Value, value.ToString()), null);
 60                                         }
 61                                         else
 62                                         {
 63                                             //将字符串转换为枚举对象
 64                                             pi.SetValue(t, Enum.Parse(queryResult.FirstOrDefault().Value, value.ToString()), null);
 65                                         }
 66                                     }
 67                                     else
 68                                     {
 69                                         if (obj != null)
 70                                         {
 71                                             pi.SetValue(obj, value, null);
 72                                         }
 73                                         else
 74                                         {
 75                                             pi.SetValue(t, value, null);
 76                                         }
 77                                     }
 78                                 }
 79                                 else {
 80                                     if (obj != null)
 81                                     {
 82                                         pi.SetValue(obj, value, null);
 83                                     }
 84                                     else
 85                                     {
 86                                         pi.SetValue(t, value, null);
 87                                     }
 88                                 }
 89                             }
 90                         }
 91                     }
 92                     T ta = default(T);
 93                     //拆箱
 94                     if (obj != null)
 95                     {
 96                         ta = (T)obj;
 97                     }
 98                     else
 99                     {
100                         ta = t;
101                     }
102                     //对象添加到泛型集合中 
103                     ts.Add(ta);
104                 }
105                 return ts;
106             }
107             else
108             {
109                 throw new ArgumentNullException("转换的集合为空.");
110             }
111         }
112 
113         /// <summary>
114         /// 泛型集合转换成DataTable
115         /// </summary>
116         /// <typeparam name="T">泛型集合类型</typeparam>
117         /// <param name="list">泛型集合对象</param>
118         /// <returns></returns>
119         public static DataTable ListGenuricConvertToDataTable<T>(List<T> list)
120         {
121             if (list?.Count > 0)
122             {
123                 Type type = typeof(T);
124                 PropertyInfo[] properties = type.GetProperties();
125                 DataTable dt = new DataTable(type.Name);
126                 foreach (var item in properties)
127                 {
128                     dt.Columns.Add(new DataColumn(item.Name) { DataType = item.PropertyType });
129                 }
130                 foreach (var item in list)
131                 {
132                     DataRow row = dt.NewRow();
133                     foreach (var property in properties)
134                     {
135                         row[property.Name] = property.GetValue(item, null);
136                     }
137                     dt.Rows.Add(row);
138                 }
139                 return dt;
140             }
141             else
142             {
143                 throw new ArgumentNullException("转换的集合为空.");
144             }
145         }
146     }

下面是测试代码

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             DataTable dt = new DataTable();
 6             dt.Columns.Add("ID", typeof(int));
 7             dt.Columns.Add("Name", typeof(string));
 8             dt.Columns.Add("USex", typeof(string));
 9             dt.Rows.Add(1, "肖潇",Sex.woman);
10             dt.Rows.Add(2, "何峰涛", Sex.man);
11             dt.Rows.Add(3, "王萌", Sex.woman);
12             dt.Rows.Add(4, "汤晓乐", Sex.man);
13             Dictionary<string, Type> dEnum = new Dictionary<string, Type>();
14             dEnum.Add("USex", typeof(Sex));
15             List<User> liUser = (List<User>)Helper.DataTableConvertToListGenuric<User>(dt, dEnum);
16             Console.WriteLine("DataTable To List<T>");
17             foreach (var item in liUser)
18             {
19                 Console.WriteLine(item.ID + ":" + item.Name+":"+item.USex);
20             }
21             Console.WriteLine("================");
22             DataTable dtConvert = Helper.ListGenuricConvertToDataTable(liUser);
23             Console.WriteLine("List<T> To DataTable");
24             foreach (DataRow item in dtConvert.Rows)
25             {
26                 Console.WriteLine(item["ID"] + ":" + item["Name"]+":"+(Sex)item["USex"]);
27             }
28             Console.ReadKey();
29         }
30     }
31 
32     struct User
33     {
34         public int ID { get; set; }
35         public string Name { get; set; }
36         public Sex USex { get; set; }
37     }
38 
39     enum Sex {
40         man = 0,
41         woman = 1
42     }

原文地址:https://www.cnblogs.com/MadisonSky/p/6837313.html