LINQ和泛型
在.net2.0中引用了泛型,泛型是我在.net 2.0众多特性中最喜欢的一个,可以说泛型给我们的编程思想上带来了不小的影响。.net2.0和.net1.1相比,很多功能用泛型和不用泛型都可以实现,例如过滤一个数组元素。但使用泛型会带来很多额外的好处,或者说泛型能办很多非泛型时代不能完成的任务。
案例一:对增删改查用面向对象进行包装,如果想把客户端与业务处理以及数据处理部分更好的解耦,如果在.net1.1时代是很难实现的。像很多开源的框架,都有强大的ORM编程模式,它使得所有的增删改查都最终统一表现在接口方法上,接受的参数正是实体对象而不依赖于具体的数据源类型。
案例二:IComparer<T>接口的扩展,IComparer<T>接口对于实体集的排序提供了非常灵活的方案,比起IComparer接口,省去了烦人的类型转换以及类型安全问题。我们还可以对IComparer<T>接口进行更进一步的封装,让它在客户端更加解耦,可以参数这篇文章:泛型真的很神奇。
案例三:对于数组或者是实体集的查询,说的直接点就是实现了IEnumerable,IEnumerable<T>或派生类型,如 IQueryable<T>接口的集合。传统的IEnumerable接口在查询数据时都需要用到foreach操作,而泛型IEnumerable接口或派生类型,如 IQueryable<T>接口,提供了更加简单而且更加高效安全的查询模式。
示例:下面一个简单的示例来说明下LINQ中的泛型应用。
//申明一个整形数组
int[] num = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
//查询数组中元素值大于1的集合
//传统方式
ArrayList listArr = new ArrayList();
foreach (int i in num)
{
if (i < 1)
{
listArr.Add(i);
}
}
//LINQ方式
//匿名类型方式
var list = from _num in num
where _num > 1
select _num;
非泛型方式的缺点:
1):从代码量来看,比LINQ方式多;
2):ArrayList相对泛型在性能上具有先天上的劣势。
3):LINQ充分利用了泛型的优点再结合LINQ优良的查询方式,使得代码的可阅读性进一步加强。
下面是我结合MSDN总结的一些LINQ中的泛型部分用法,不足处忘指正。
第一:LINQ查询中的IEnumerable<T>变量。下面代码中显示类型方式中IEnumerable<int>,就表明查询出来的集体里面都只会存放0个或者n个整形类型的数据。
//显示类型方式
IEnumerable<int> list2 = from _num in num
where _num > 1
select _num;
第二:系统推断变量类型。由于.net3.0推出了匿名类型,所以我们可以把IEnumerable<int>直接写成var,让系统去判断变量的类型。
//匿名类型方式
var list = from _num in num
where _num > 1
select _num;
第三:查询操作中的类型关系,第二条中我们知道可以引用匿名类型来让系统来判断变量的类型,但要写出有效的查询,我们最好了解对象之间的关联关系。LINQ 查询操作在数据源、查询本身及查询执行中是强类型的。查询中变量的类型必须与数据源中元素的类型和 foreach 语句中迭代变量的类型兼容。
1):查询操作中不需要转换数据源。查询的结果集元素类型和数据源元素类型相同。第一条中的显示类型方式查询中,记录集元素类型为IEnumerable<int>,如果我们要对集合做foreach操作,我们需要这样写:
foreach (int i in list2)
{
//dosomething
}
foreach (var i in list2)
{
//dosomething
}
2):查询操作中需要类型转换。如果原始数据源和最后查询数据源的元素类型不同,说明需要类型转换,下面是一个学生类的集合,但我们只需要返回满足条件的学生的电话号码并不需要其它信息,这里为了查询的有效性,并不需要满足条件学生的所有信息,即不需要返回整个student,这相当是SQL中的select *。下面是一个学生类:
/// <summary>
/// 学生实体
/// </summary>
class student
{
/// <summary>
/// 姓
/// </summary>
public string sFirst
{
get;
set;
}
/// <summary>
/// 名
/// </summary>
public string sLast
{
get;
set;
}
/// <summary>
/// 电话
/// </summary>
public string sPhone
{
get;
set;
}
}
构造学生数据源
//学生姓名电话集合
IEnumerable<student> listStudent = new List<student> {
new student {sFirst = "张",sLast ="三",sPhone ="1111111"},
new student {sFirst ="李",sLast ="四",sPhone ="2222222"},
new student {sFirst ="李",sLast ="明",sPhone ="3333333"}
};
查询姓李的学生的电话号码.
IEnumerable<string> listStudentQuery = from item in listStudent
where item.sFirst == "李"
select item.sPhone;
猜测: 如果原始数据源实现了IEnumerable或者是IEnumerable<T>,那么查询出来的结果集也会实现数据源的接口。这里没有找到相关资料,有的朋友方便给出下。所以类型为IEnumerable<student>的数据源,得到的查询结果也会实现IEnumerable<T>接口。
错误查询:
IQueryable <string> listStudentQuery2 = from item in listStudent
where item.sFirst == "谷"
select item.sPhone;
3):让系统完全代理数据类型推断操作。即查询时我们不显示指定数据类型。查询姓李的学生的电话号码
var listStudentQuery2 = from item in listStudent
where item.sFirst == "谷"
select item.sPhone;
foreach (var s in listStudentQuery2)
{
//dosomething
}