linq语法基础使用示例
借助于linq技术,我们可以使用一种类似sql的语法来查询任何形式的数据。从技术角度而言,linq定义了大约40个查询操作符,如from, select, in, where, group by, orderby, … 使用这些操作符可以编写查询语句。
做软件的,总想代码要怎么样才能更好地复用,要怎么样才更利于扩展,要怎么样更能以不变应万变。就如同微软框架所提供的api一样,在一定程度上避免开发者重复造*。拿linq来说吧,.net framework3.5及之后的版本都已经封装进去,供成千上百万的开发者使用。同一套linq语法,它能支持linq to objecct、linq to xml、linq to database。复用、减少开发工作量及降低学习成本等好处都是不言而喻的。linq的学习很像sql,所以有使用过sql语句的话,感觉还是蛮熟悉的。
上手简单是学习linq的一大好处,语法很像sql语句的语法。而且学一种技术,可以当多种技术来使用。这是不是很像那种多功能刀,一刀在手,生活无忧。linq支持集合、xml、数据库的查询。写代码就像说话,多必失,所以呢,尽量优化自己的代码。这不但有利于减少错误的发生,也有利于提高生产率、降低维护的成本。而使用linq也是奔着这个方向发展。
坦白说,我看到网上有很多linq方面的教程,知识面介绍都挺好。我只能是厚着脸皮,站在巨人的肩膀上驰骋。本文基本是源于博友08年的文章,感觉他写的很好。虽然抄袭是很可耻的行为,但是回想大学能顺利毕业,论文也是东抄一块,西抄一块。所以现在我是很“蛋定”了。我要响应鲁老爷的拿来主义精神。
linq是一种查询语言,所以呢,运用的场景当然也就是查询罗。查哪些,包括linq to objecct、linq to xml、linq to database。可以说查询的范围很广。每一种都可以出一系列的文章,我们这里主要还是讲 linq to objecct。
来看看从集合中,我们是怎么来查询需要的值。
using system;
using system.collections.generic;
using system.linq;
using system.text;
namespace linqapplication
{
class people
{
/// <summary>
/// 名字
/// </summary>
public string firstname { get; set; }
/// <summary>
/// 姓氏
/// </summary>
public string lastname { get; set; }
/// <summary>
/// 国家
/// </summary>
public string country { get; set; }
}
class program
{
static void main(string[] args)
{
list<people> listpeople = new list<people>()
{
new people{firstname="peter",lastname="zhang",country="china"},
new people{firstname="alan",lastname="guo",country="japan"},
new people{firstname="linda",lastname="tang",country="china"}
};
list<people> result = new list<people>();
foreach (people p in listpeople)
{
if (p.country == "china")
{
result.add(p);
}
}
foreach(people p in result)
{
console.writeline("your name is :" + p.firstname + " " + p.lastname);
}
console.readkey();
}
}
}
上面的方法可以说是最直接,最容易想到的方法。上面的实现怎么看也没有觉得有什么好复用的,但是事实是怎么样?就有牛人看出了名堂,善于归纳上面的问题就是判断是跟不是的问题,就想到要去提出来,供以后复用。 当然复用之路也不是一蹴而就的,也是日积月累而成。所以我们也来看看过渡的过程。
/// <summary>
/// 判断是否存在
/// </summary>
/// <param name="p">对象</param>
public static bool isexist(people p)
{
return p.country == "china";
}
如果说只是如下方式来实现的话,那还真是白费力气了。
foreach (people p in listpeople)
{
if (isexist(p))
{
result.add(p);
}
}
但是结合到委托的话,我们就可以把isexist(people p)当成一个参数来进行传递。这里我们过渡再快一点,我们把查询的那一段代码提到另一类helper供以后得用。我们来看看helper类的代码实现。限于篇幅的问题,只截helper类的方法。
public class helper
{
//声明委托
public delegate bool existpeople(people p);
/// <summary>
/// 获取满足条件的数据
/// </summary>
/// <param name="listpeople">数据集</param>
/// <param name="existpeople">条件</param>
public static list<people> getpeopleresult(ilist<people> listpeople, existpeople existpeople)
{
list<people> result = new list<people>();
foreach (people p in listpeople)
{
if (existpeople(p))
{
result.add(p);
}
}
return result;
}
}
这样我们就可以直接调用,来获取满足条件的数据了。也可以使用c#2.0提供的匿名委托,还可以使用c#3.0的lambda表述式。代码如下:
static void main(string[] args)
{
list<people> listpeople = new list<people>()
{
new people{firstname="peter",lastname="zhang",country="china"},
new people{firstname="alan",lastname="guo",country="japan"},
new people{firstname="linda",lastname="tang",country="china"}
};
ilist<people> result = new list<people>();
//直接调用
result = helper.getpeopleresult(listpeople, isexist);
//匿名委托
//result = helper.getpeopleresult(listpeople, delegate(people p){ return p.country == "china" ? true : false;});
//lambda表达式
//result = helper.getpeopleresult(listpeople, people => people.country == "china");
foreach(people p in result)
{
console.writeline("your name is :" + p.firstname + " " + p.lastname);
}
console.readkey();
}
讲到这里,对于具体集合的查询基本上是完成了,但是呢,c#3.0还提供了一种方法,使调用的代码更加直观,那就是扩展方法。通过扩展ilist集合的方法,我们就可以通过ilist来调用并传递委托条件即可。
helper类的扩展代码如下:
public static class helper
{
//声明委托
public delegate bool existpeople(people p);
/// <summary>
/// 获取满足条件的数据
/// </summary>
/// <param name="listpeople">数据集</param>
/// <param name="existpeople">条件</param>
public static ilist<people> getpeopleresult(this ilist<people> listpeople, existpeople existpeople)
{
list<people> result = new list<people>();
foreach (people p in listpeople)
{
if (existpeople(p))
{
result.add(p);
}
}
return result;
}
}
我们看main方法的调用,是不是很直观了,就像调用集合的方法,并给传递委托条件即可了。main方法如下:
static void main(string[] args)
{
list<people> listpeople = new list<people>()
{
new people{firstname="peter",lastname="zhang",country="china"},
new people{firstname="alan",lastname="guo",country="japan"},
new people{firstname="linda",lastname="tang",country="china"}
};
ilist<people> result = new list<people>();
//直接调用
//result = helper.getpeopleresult(listpeople, isexist);
//匿名委托
//result = helper.getpeopleresult(listpeople, delegate(people p){ return p.country == "china";});
//lambda表达式
//result = helper.getpeopleresult(listpeople, people => people.country == "china");
//扩展方法调用
result = listpeople.getpeopleresult(people => people.country == "china");
foreach(people p in result)
{
console.writeline("your name is :" + p.firstname + " " + p.lastname);
}
console.readkey();
}
上面是使用getpeopleresult方法名,但是我们想要的话,是不是就可以实现诸如select、where、orderby等方法了。基本上方法的介绍就已经完了。但是有一个大的问题,那就是它还比较死,不灵活,因为我们不可能说每个集合里面的对象(本文是people)都重复来写。这里肯定是需要提供一种方式,使它能够接受不同的对象,这样才有利于我们复用。因为ilist继承自ienumerable,所以可以给ienumerable实现扩展方法,然后利用泛型的特征,就可以给不同的对象来复用,代码如下:
public static class helper
{
public delegate bool condtion<t>(t t);
public static ienumerable<t> getpeopleresult<t>(this ienumerable<t> items, condtion<t> condition)
{
foreach (t t in items)
{
if (condition(t))
{
//c# 2.0里出现的一个关键字,返回一个迭代器
yield return t;
}
}
}
}
main方法就不贴全部了,毕竟上面都重复好几回,只贴调用那一句:
ienumerable<people> result = helper.getpeopleresult<people>(listpeople, people => people.country == "china");
而c# 3.0则给我们提供var关键字,被称为推断类型。
var 关键字能指示编译器根据初始化语句右侧的表达式推断变量的类型。推断类型可以是内置类型、匿名类型、用户定义类型、.net framework 类库中定义的类型或任何表达式。所以上面的式子可以写成如下方式:
var result = helper.getpeopleresult<people>(listpeople, people => people.country == "china");
正式结束
上一篇: 浅谈Java多线程实现及同步互斥通讯