从机房开始没多长时间的时候就听同学们说要是用泛型集合,但是那时候还不是很了解,想着要有一个过渡,不能刚刚学会了最就想着跑,当机房完成一半的时候,开始使用泛型集合,但是一直没有对泛型进行一个小结,现在对泛型说一下自己的理解。
首先说一下使用DataTable时的情况
使用DataTable时,查询到数据后直接通过它返回到B层和U层了,这样对于数据库的安全性是不能保证的,而且将查询到的数据返还到窗体时,必须知道数据库中对应的字段的位置,这样和数据库的耦合性太大,这和第一次机房中的代码的思想就一样了,是一种面向过程的思想并不符合面向对象的思想。比如在U层中,使用DataTable的代码为:
<span style="font-family:KaiTi_GB2312;font-size:18px;"> txtStudentNo.Text = dt.Rows(0).Item(2) txtName.Text = dt.Rows(0).Item(3) txtSex.Text = dt.Rows(0).Item(4) txtTie.Text = dt.Rows(0).Item(5) txtGrade.Text = dt.Rows(0).Item(6) txtClass.Text = dt.Rows(0).Item(7) txtStatus.Text = dt.Rows(0).Item(11) txtExplain.Text = dt.Rows(0).Item(9) txtBalance.Text = dt.Rows(0).Item(8)</span>这是在数据较少的情况下,我们可以想象如果有数据较多的话,DataTable会有意想不到的麻烦,所以使用泛型有很多优点。
什么是泛型
泛型是具有占位符(类型参数)的类、结构、接口的方法,这些占位符是类、结构、接口和方法所存储或使用的一个或多个类型的占位符。泛型集合类可以将类型参数用作它所存储的对象的类型的占位符;参数类型作为其字段的类型和其方法的参数类型出现。
泛型集合需要System.Collection.Generic的命名空间,它在用法上的关键就是在IList和List后面加‘<T>’,这个‘T’就是我们需要指定的集合的数据或对象类型。
为什么要引用泛型
泛型的使用是有一个过程的,最开始用内存中一个位置映射一个值,用变量来“使用”这个值。进一步发展,用变量来引用一组值,这就是数组。数组是我们是我们经常使用的,但是数组的还是有一些缺点在的,数组的使用是要定义长度的,而且在两个数据中间插入一个数据是很麻烦的。所以工程师们使用了ArrayList(集合)来规避这些问题。它是更强大的数组,需要依赖于Object基类。这样在我们使用ArrayList中的数据来处理问题的时候,很可能会报类型不匹配的错误,
在使用的时候,我们需要将它们转化为对应的原类型来处理,于是都得转为Object,涉及到装箱,使性能下降,特别是元素量巨大时,会带来很大的性能损耗。基于集合的这种缺点,我们引入了泛型。(如想更详细的了解单击此处)
如何使用泛型
在sqlhelper中进行查询的功能时返回的都是datatable类型的,所以我们需要进行一下转换,转换成list集合泛型,与sqlhelper一样,为了减少代码的重复量,进行代码的复用,我们将这个方法抽象出来放在D层以调用,代码如下:
<span style="font-family:KaiTi_GB2312;font-size:18px;">Imports System.Collections.Generic Imports System.Reflection '****************************** '类名称:ModelHelper '命名空间:DAL '功能:实现datatable对实体的转换功能 '创建时间:2015-4-30 11:04:49 '作者:WWW '********************************* Public Class ModelHelper 'Public Shared Function ConvertToList(Of T As New)(dt As DataTable) 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 'If value IsNot Nothing 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 </span>
下面介绍其他层的代码,以学生查看余额为例:
接口层的代码:
<span style="font-family:KaiTi_GB2312;font-size:18px;"> ''' <summary> ''' 学生查余额,使用视图和泛型,对原来使用超体进行重新修改 ''' </summary> ''' <param name="card"></param> ''' <returns></returns> ''' <remarks>2015-5-4 09:45:18</remarks> Function CashInquire(ByVal card As Entity.EntityCard) As List(Of Entity.EntityCard)</span>D层代码,使用泛型的时候首先需要定义:
<span style="font-family:KaiTi_GB2312;font-size:18px;"> ''' <summary> ''' 学生查看余额 ,使用了视图和list泛型,对原来编写的重新进行修改 ''' 查询卡号存在的情况下才会查询到数据 ''' </summary> ''' <param name="card"></param> ''' <returns></returns> ''' <remarks>2015-5-4 09:54:22</remarks> Public Function CashInquire(card As EntityCard) As List(Of EntityCard) Implements ICard.CashInquire Dim sql As String Dim table As DataTable Dim list As New List(Of Entity.EntityCard) Dim sqlparams As SqlParameter() = {New SqlParameter("@CardNo", card.CardNo)} sql = "select * from V_QueryCash where CardNo=@CardNo" table = sqlHelper.ExecSelect(sql, CommandType.Text, sqlparams) list = DAL.ModelHelper.convertTolist(Of Entity.EntityCard)(table) Return list End Function</span>B层代码,需要定义一个list:
<span style="font-family:KaiTi_GB2312;font-size:18px;"> ''' <summary>实现抽象工厂和接口的方法 ''' 学生查看余额,返回泛型。重新修改。可判断卡号是否存在 ''' </summary> ''' <param name="card"></param> ''' <returns></returns> ''' <remarks>2015-5-4 10:02:58</remarks> Public Function CashInquire(ByVal card As Entity.EntityCard) As List(Of Entity.EntityCard) Dim factory As New Factory.FactoryDB Dim Icard As IDAL.ICard Dim list As New List(Of Entity.EntityCard) '实例化泛型 Icard = factory.CreateCard list = Icard.CashInquire(card) Return list End Function</span>U层部分代码,与datatable不同的是不需要知道它在数据表的哪个字段,只要list(*)+‘.’就可以了:
<span style="font-family:KaiTi_GB2312;font-size:18px;"> Dim Encard As New Entity.EntityCard Dim CashInquireBLL As New BLL.CardBLL Dim list As New List(Of Entity.EntityCard) '根据卡号的情况,进行查询 Encard.CardNo = txtCardNo.Text.Trim() list = CashInquireBLL.CashInquire(Encard) If list.Count > 0 Then '如果有数据 txtStudentNo.Text = list(0).StudentNo txtBalance.Text = list(0).TotalAmount txtClass.Text = list(0).SClass txtComment.Text = list(0).Comment txtDepartment.Text = list(0).Department txtGrade.Text = list(0).Grade txtName.Text = list(0).Name txtSex.Text = list(0).Sex txtStatus.Text = list(0).Status</span>需要注意的问题:
使用泛型时要保证实体的属性名字必须和数据库中的字段的名字是一模一样的,否则不能正常的返回数据。我就是因为不一样导致不能将信息返回到窗体中,所以调了很久才知道这个原因。
总结:
学习到一个新的东西要好好的运用,同时思考它的意义和好处是什么,不断的学习,这样才能不断的进步。现在我所了解到的泛型只是冰山一角,相信在以后的学习中会对泛型有更深的理解。