前言:
在机房重构的过程,以学生查看余额为例功能为例,我刚开始会从D层传回一个datable类型的表,一直传到了U层,然后再根据datable的行号和列号往各个文本框中赋值,这样我就必须要知道数据库中字段的结构顺序,这样U层和D层之间的耦合大大增大,这当然不是我们想要的了,还有一点是有时我想返回一个datatable类型的表和一个Boolean类型,如何同时返回多种类型的数据?这就引来了泛型。
泛型了解:
泛型其实就是一个整理箱,里面可以存放各种类型的物品,看了雪芬的博客,把泛型比喻为我们取来的快递箱子,我们想一下,当我们买了面膜,一个精致的盒子里面放着好多张面膜,这样只通过一个盒子就可以把所有的面膜取回来,通过盒子把买来的额物品封装到一了一起,而这个盒子就相当于我们泛型中定义的List,面膜就是List中的元素。
下面是数组,集合,泛型的比较:
数组 | 只能放定义类型的元素,不会自动增大,取出时不用做类型转换 |
集合 | 可放任意类型的元素,会自动增大,取出时要做类型转换 |
泛型
| 只能放定义类型的元素,会自动增大,取出时不用做类型转换 |
泛型中<List(Of T)>,T就是一个要引用的实体,对象,就是List的一个参数。一个泛型里可以包含同一个类型的很多实体。下图详细地描述了如何将datatable类型的数据转化为List:
泛型的使用方法:
1.定义泛型:
Dim list As New List(Of T)
2.使用泛型
我们从数据库查询出来的数据是datatable类型的,如何将datatable类型的数据转化为List类型呢?这时我们需要定义一个把datable类型的数据转化为List类型的类:
Imports System.Reflection
'实现datatable对实体的转换功能
Public Class ModelHelper
Public Shared Function convertTolist(Of T As {New})(ByVal dt As DataTable) As IList(Of t)
'获得T的类型
Dim type As Type = GetType(T)
Dim ts As New List(Of T)
'定义一个临时变量
Dim strTemp As String = String.Empty
'遍历表中所有的行数
For Each dr As DataRow In dt.Rows
'定义类型变量Act获取动态创建对象T的类型
Dim act As T = If((Nothing Is Nothing), Activator.CreateInstance(Of T)(), Nothing)
'引用反射表示可获得对象的所有属性组成的集合
Dim propertys As PropertyInfo() = act.[GetType]().GetProperties()
'定义array变量,接收propertys中含有的属性,并提供对属性propertys元数据访问
Dim array As PropertyInfo() = propertys
Dim intCount As Integer = 0
'遍历所有对象属性
While intCount < array.Length 'length表示所有维数中元素的总和
'pr表示元素中含有的属性,并提供对数据访问
Dim pr As PropertyInfo = array(intCount)
strTemp = pr.Name
'列名=对象的属性名
If dt.Columns.Contains(strTemp) Then
'判断此属性是否设置函数
If pr.CanWrite Then '该属性是否可写
Dim value As Object = dr(strTemp)
'如果非空,则赋值给对象的属性
If value IsNot DBNull.Value Then
'设置对象的属性值。
pr.SetValue(act, value, Nothing)
End If
End If
End If
intCount += 1
Continue While
End While
'添加对象到泛型集合中
ts.Add(act)
Next
Return ts
End Function
End Class
方法convertTolist,是把DataTable类型的dt转化为T类型的。在学生查看余额中,通过输入的卡号Cardno得到了一条记录datatable类型的dt,然后把dt中对应的字段值放到显示余额信息的CardInfo实体中,这样CardInfo就作为List的一个元素返回。
Public Shared Function convertTolist(Of T As {New})(ByVal dt As DataTable) As IList(Of t)
(1).实体的属性名称必须和数据表字段的名称一致。因为它会去判断如果过数据库中字段包含实体中属性,就会把字段所对应的值赋给属性,如果实体属性名称和数据库字段名称不一致,就会返回Null值。
If dt.Columns.Contains(strTemp) Then
'判断此属性是否设置函数
If pr.CanWrite Then '该属性是否可写
Dim value As Object = dr(strTemp)
'如果非空,则赋值给对象的属性
If value IsNot DBNull.Value Then
'设置对象的属性值。
pr.SetValue(act, value, Nothing)
End If
End If
End If
(2)类型转换
当在执行的出了如下的错误:类型System.String的对象无法转化为类型“System.Char”原来是因为我把所有数据都转为了string的类型,而在实体CardInfo中我定义的却是Char类型。这样就会出现如下的错误。
解决办法:把实体中属性改为string类型即可。
3.读取泛型中的值:
list(0)代表的是List中第一条记录,这样我们直接通过实体的属性对UI层的textbox进行赋值就可以,而不需要知道数据库中的字段信息。下面就是把泛型中第0条记录CardInfo中的属性读取出来。
txtSid.Text = list(0).studentNo
txtName.Text = list(0).studentName
txtSex.Text = list(0).sex
txtDepartment.Text = list(0).department
txtGrade.Text = list(0).grade
txtClass.Text = list(0).classNo
txtState.Text = list(0).Status
txtBalance.Text = list(0).Status
总结:
通过泛型来封装数据,把数据传到UI层,实际泛型里存放的很多的实体,而泛型只是个桶,通过泛型很好地保证了七层结构,使得各层之间的耦合度极度降低,但是使用Datatable类型的话,在UI层就必须要知道数据库的结构,打破了七层的结构。
刚开始我一直是用的Datatable,后来听雪芬说要先了解泛型,所以我就试着在网上搜了很多泛型的使用方法,当然遇到了很多的问题,但是在调错的过程中就理解了,现在我们的目的不是实现功能,而是想应该怎样减少代码,增强代码的可复用,以及系统的扩展性,灵活性,使得系统达到最优,这样学起来就会很有意思,以前接触到的很多但是还不理解的东西(如设计模式,存储过程,视图等)都是我们学习的机会。