实例化泛型对象,将DataRow转换成相应的对象(通用以及泛型操作)

一直以来对框架非常感兴趣,对大多数框架(目前本人看过的)来说一般分为三个部分:
(1):拼接SQL语句(反射)。
(2):执行CRUD操作,获取相应的DataTable、DataSet等等。
(3):将相应的DataTable、DataSet转换成对象(反射)。
因此可以将上述3个部分各个击破,一步一步来实现自己的框架,看的框架多了,也就成了路实例化泛型对象,将DataRow转换成相应的对象(通用以及泛型操作)。反射在这里面被淋漓尽致的运用,哈哈,站在款哥的肩膀上......
(一)通用以及泛型转换代码
先看下面关于将DataRow转换成相应的对象(通用以及泛型操作)的方法(这里仅仅是对DataRow进行转换,对于将DataTable转换成对象集合,思路基本差不多,因此本例里不再对其他的进行相关代码的编写):
1 public class Mapper 2 { 3 public static object ToEntity(DataRow adaptedRow, Type entityType) 4 { 5 if (entityType == null || adaptedRow == null) 6 { 7 return null; 8 } 9 10 object entity = Activator.CreateInstance(entityType); 11 CopyToEntity(entity, adaptedRow); 12 13 return entity; 14 } 15 16 public static T ToEntity(DataRow adaptedRow, T value) where T:new() 17 { 18 T item = new T(); 19 if (value == null || adaptedRow == null) 20 { 21 return item; 22 } 23 24 item = Activator.CreateInstance(); 25 CopyToEntity(item, adaptedRow); 26 27 return item; 28 } 29 30 public static void CopyToEntity(object entity, DataRow adaptedRow) 31 { 32 if (entity == null || adaptedRow == null) 33 { 34 return; 35 } 36 PropertyInfo[] propertyInfos = entity.GetType().GetProperties(); 37 38 foreach (PropertyInfo propertyInfo in propertyInfos) 39 { 40 if (!CanSetPropertyValue(propertyInfo, adaptedRow)) 41 { 42 continue; 43 } 44 45 try 46 { 47 if (adaptedRow[propertyInfo.Name] is DBNull) 48 { 49 propertyInfo.SetValue(entity, null, null); 50 continue; 51 } 52 SetPropertyValue(entity, adaptedRow, propertyInfo); 53 } 54 finally 55 { 56 57 } 58 } 59 } 60 61 private static bool CanSetPropertyValue(PropertyInfo propertyInfo, DataRow adaptedRow) 62 { 63 if (!propertyInfo.CanWrite) 64 { 65 return false; 66 } 67 68 if (!adaptedRow.Table.Columns.Contains(propertyInfo.Name)) 69 { 70 return false; 71 } 72 73 return true; 74 } 75 76 private static void SetPropertyValue(object entity, DataRow adaptedRow, PropertyInfo propertyInfo) 77 { 78 if (propertyInfo.PropertyType == typeof(DateTime?) || 79 propertyInfo.PropertyType == typeof(DateTime)) 80 { 81 DateTime date = DateTime.MaxValue; 82 DateTime.TryParse(adaptedRow[propertyInfo.Name].ToString(), 83 CultureInfo.CurrentCulture, DateTimeStyles.None, out date); 84 85 propertyInfo.SetValue(entity, date, null); 86 } 87 else 88 { 89 propertyInfo.SetValue(entity, adaptedRow[propertyInfo.Name], null); 90 } 91 } 92 }

以上的代码主要是针对将DataRow转换成相应的对象,方法为
(1)public static object ToEntity(DataRow adaptedRow, Type entityType) (2)public static T ToEntity(DataRow adaptedRow, T value) where T:new()
(二)Activator 类
对于Activator 类,主要为以下3个比较常用,包括对object和T的对象实例化。
1 public sealed class Activator : _Activator 2 { 3 public static T CreateInstance(); 4 public static object CreateInstance(Type type); 5 public static object CreateInstance(Type type, params object[] args); 6 }
(三)PropertyInfo的灵活运用
一般情况下,我们会对PropertyInfo进行灵活运用,以达到相应的目标,这是大家惯用的伎俩,哈哈。
先根据Type.GetProperties()获取该类型的所有属性,返回为属性数组PropertyInfo[]。
PropertyInfo[] propertyInfos = entity.GetType().GetProperties();
然后对PropertyInfo[] 进行相应的操作。
相应的PropertyInfo 主要有以下几个常用的方法,如下:
1 public abstract class PropertyInfo : MemberInfo, _PropertyInfo 2 { 3 public static bool operator !=(PropertyInfo left, PropertyInfo right); 4 public static bool operator ==(PropertyInfo left, PropertyInfo right); 5 6 public abstract bool CanRead { get; } 7 public abstract bool CanWrite { get; } 8 public abstract Type PropertyType { get; } 9 10 public virtual object GetValue(object obj, object[] index); 11 public abstract object GetValue(object obj, BindingFlags invokeAttr, Binder binder, object[] index, CultureInfo culture); 12 13 public virtual void SetValue(object obj, object value, object[] index); 14 public abstract void SetValue(object obj, object value, BindingFlags invokeAttr, Binder binder, object[] index, CultureInfo culture); 15 }
还有一个比较重要的属性:public abstract string Name { get; }
以上对象相应的方法的实例和运用请参考MSDN。
(四)相关的单元测试如下:
以上的2个主要方法的单元测试如下:
1 [TestMethod()] 2 public void ToEntityTest() 3 { 4 Information information = CreateNewItem(); 5 6 DataRow adaptedRow = CreateNewDataRow(information); 7 Type entityType = typeof(Information); 8 Information actual = (Information)Mapper.ToEntity(adaptedRow, entityType); 9 10 AssertInformationState(information, actual); 11 } 12 13 /// 14 ///ToEntity 的测试 15 /// 16 [TestMethod()] 17 public void ToEntityGenericTest() 18 { 19 Information information = CreateNewItem(); 20 DataRow adaptedRow = CreateNewDataRow(information); 21 22 Information actual = (Information)Mapper.ToEntity(adaptedRow,information); 23 24 AssertInformationState(information, actual); 25 } 26 27 private static void AssertInformationState(Information information, Information actual) 28 { 29 Assert.IsNotNull(actual); 30 Assert.IsNull(actual.Address); 31 Assert.IsNull(actual.Region); 32 Assert.AreEqual(information.Id, actual.Id); 33 Assert.AreEqual(information.Name, actual.Name); 34 Assert.AreEqual(information.CreateDate, actual.CreateDate); 35 } 36 37 private static Information CreateNewItem() 38 { 39 Information information = new Information() 40 { 41 Id = 0, 42 Name = "Jasen", 43 CreateDate = DateTime.Now, 44 Region = null 45 }; 46 47 return information; 48 } 49 50 private DataRow CreateNewDataRow(Information information) 51 { 52 DataTable table= CreateTempTable(); 53 DataRow row= table.NewRow(); 54 55 row["Name"] = information.Name; 56 row["CreateDate"] = information.CreateDate; 57 table.Rows.Add(row); 58 59 return table.Rows[0]; 60 } 61 62 private DataTable CreateTempTable() 63 { 64 DataTable namesTable = new DataTable("Temp"); 65 66 DataColumn idColumn = new DataColumn(); 67 idColumn.DataType = System.Type.GetType("System.Int32"); 68 idColumn.ColumnName = "id"; 69 idColumn.AutoIncrement = true; 70 namesTable.Columns.Add(idColumn); 71 72 DataColumn nameColumn = new DataColumn(); 73 nameColumn.DataType = System.Type.GetType("System.String"); 74 nameColumn.ColumnName = "Name"; 75 nameColumn.DefaultValue = "Name"; 76 namesTable.Columns.Add(nameColumn); 77 78 DataColumn createDateColumn = new DataColumn(); 79 createDateColumn.DataType = System.Type.GetType("System.DateTime"); 80 createDateColumn.ColumnName = "CreateDate"; 81 namesTable.Columns.Add(createDateColumn); 82 83 DataColumn regionColumn = new DataColumn(); 84 regionColumn.DataType = System.Type.GetType("System.String"); 85 regionColumn.ColumnName = "Region"; 86 namesTable.Columns.Add(regionColumn); 87 88 DataColumn[] keys = new DataColumn[1]; 89 keys[0] = idColumn; 90 namesTable.PrimaryKey = keys; 91 92 return namesTable; 93 }

以上的2处标识红色的代码段为主要的验证逻辑,代码应该比较清晰以及简单,故本人不会讲解其中的代码。
总的来说,对于将DataRow转换成相应的对象或者泛型,主要是通过反射来进行操作的。以前也看到过很多别人写的相关类似的功能,不过很多都是不怎么好的,BUG无数.......莫名其妙的,哈哈,跟款哥混了一阵,也开始偶尔对代码眼光挑剔了,近朱者赤,近墨者黑,还真是这么一回事。以前做个什么,只要基本功能实现了,谁还去管它呢!现在代码改个几遍,依旧还是会仔细去看、去想,尽量会去考虑各种情况。现在发现自己变了,哈哈.....
源代码下载:DataRow转换成对象源代码下载
Tags:  泛型编程与stl map泛型 泛型编程 java泛型 实例化泛型对象

延伸阅读

最新评论

发表评论