走进Linq-Linq大观园
2008-07-18 11:26 横刀天笑 阅读(3771) 评论(27) 编辑 收藏 举报本系列文章
走进Linq-Linq横空出世篇
走进Linq-辉煌的背后
走进Linq-Linq大观园
走进Linq-Linq to Objects(上)基础篇
文章发布后大家有些人叫做,心里窃喜,不过压力也大增,我很想按照简洁明快的文风写下去,不过讲技术的文章很难不落于沉闷,所以我努力了。(题外话:这几天猛看幽默小说,想把文字写的幽默一点,开个玩笑,呵呵)
经过几天的闭关编程大师又有了一些新的觉悟了,不管对DSL还是命令式编程和函数式编程都有了新的理解。如是他又接着了漫长的云游。第一站当然就是那个曾经让他结下心结的那个刚毕业的coder.
大师:“嘿,这几日可好,还在发牢骚么?”
Coder:“不了,正好你来了,让你看看我的程序”,Coder将他的电脑屏幕转向大师,期盼的眼神表明他急切的期望得到大师的夸奖。
如是大师看到了如下一些代码:
/// 一个通用的泛型委托,代表接受一个参数并有一个返回值的方法
/// </summary>
/// <typeparam name="TInput">输入参数类型</typeparam>
/// <typeparam name="TOutput">返回值类型</typeparam>
/// <param name="input">输入参数</param>
/// <returns>返回值</returns>
public delegate TOutput MyDelegate<TInput,TOutput>(TInput input);
/// <summary>
/// 这个类是包含有对IEnumerable<T>接口的一系列扩展方法
/// 因为在.net里所有的集合类都实现了IEnumerable<T>接口
/// 所以对该接口的扩展将扩散到所有集合
/// </summary>
public static class Extension
{
public static IEnumerable<TInput> Where<TInput>(this IEnumerable<TInput> self, MyDelegate<TInput, bool> filter)
{
foreach (TInput item in self)
if (filter(item))
yield return item;
}
public static IEnumerable<TOutput> Select<TInput, TOutput>(this IEnumerable<TInput> self, MyDelegate<TInput, TOutput> selector)
{
foreach(TInput item in self)
yield return selector(item);
}
//下面有更多的SQL风格的移植
}
下面是我做的个小测试代码:
{
public static void Main()
{
IList<Book> books = new List<Book> {
new Book { Title = "Inside COM", ISBN = "123-456-789",Price=20 },
new Book { Title = "Inside C#", ISBN = "123-356-d89",Price=100 },
new Book { Title = "Linq", ISBN = "123-d56-d89", Price = 120 }
};
var result = books.Where(book => book.Title == "Linq").Select(book => new {
Key = book.Title,Value=book.Price
});
}
}
编程大师一边听着coder的讲解,一遍频频点头:“傻小子,不错啊,有点当年我的影子,按照你这样下去罗马也可以建成了,Linq也是可以写出来的呀。”
Coder听到大师的话兴奋异常,不过他从这句话里还是捕捉到了一个陌生的词汇:Linq。他用诧异的眼神看着大师,问道:”啥是Linq,是谁家又创造了个新词汇?”
大师笑着说,其实你刚才做的微软已经帮你做了,还给它起了一个非常洋气的名字:Linq,中文名字呢就叫做 语言集成查询。
在.net 3.5发布的时候,微软新发布了几个dll,其中有一个就叫做System.Core.dll,在这个dll下对一些System命名空间做了进一步扩展。
在System.Core.dll下的System命名空间下你会发现有这么几个泛型的委托:
public delegate TResult Func<TResult>();
//有一个参数和一个返回值,和你那个MyDelegate一样
public delegate TResult Func<T, TResult>(T arg);
//两个参数一个返回值
public delegate TResult Func<T1, T2, TResult>(T1 arg1, T2 arg2);
//三个参数一个返回值
public delegate TResult Func<T1, T2, T3, TResult>(T1 arg1, T2 arg2, T3 arg3);
//四个参数一个返回值
public delegate TResult Func<T1, T2, T3, T4, TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4);
有了这几个泛型的委托基本上都能应付了吧。
还是在这个dll下有个System.Linq命名空间,这是Linq的核心命名空间,这里面有个名为Enumerable的静态类,它里面的方法都是对IEnumerable<T>(这个接口可是Linq的中心人物啊)这个接口的扩展方法。看看,是不是在SQL里能用的这里都能找到了?
Select,Where,OrderBy, OrderByDescending,Average,Distinct
所以你现在很简单的就可以写出像下面这样的代码了:
.OrderBy(book=>book.Price)
.Select(book=>new{Key=book.Title,Value=book.Price});
还没等coder说出口大师就在键盘上敲下:
程序=代码+数据
编程大师如是接着说:那这些数据平时都来源于哪里?
Coder:程序中自己构造的一些集合对象,像我刚才的代码中那样,还有数据库,这个使我们平时用到最多的,还有XML存储,还有WebService,这个来源于远程的数据,还有什么RSS啦等等,很多了。
编程大师:嗯,是的。数据的来源非常广泛,就说我们平常用的三个吧,内存中的集合对象、XML存储和数据库。对于内存中的集合对象我们有语言自身的支持,XML我们有XML的一些API,比如XPath,对于数据库我们有ADO.net,可实际上从抽象层面我们对这些数据的操作都是相同的,你想不想屏蔽掉存储的细节,在高层有一个统一的API访问这些数据呢?至于数据存储在哪里对于你是透明的,也许它存在于你内存中,也许在万网的机房也许在美国西雅图,但是对于你来说这些都无需关心,你的代码都一样。
Coder:听起来是个很美妙的事情,这不会是在做梦吧。
大师:不是在做梦,今天你已经有了这些方法
在.net 3.5里微软还发布了另外两个dll:
System.Data.Linq.dll
System.Xml.Linq.dll
在System.Data.Linq.dll里,对数据库的查询做了支持,不过目前微软提供的只支持Sql Server,感谢开源社区,现在有了DbLinq,它提供了对MySql,Oracle,Sql Server,PostgreSql,Sqlite的支持。
System.Xml.Linq.dll在更高层次对Xml的访问做了支持
这样你从微软这里获得了:
Linq to Objects 对内存中的集合的支持
Linq to Xml 对Xml的支持
Linq to SQL 对Sql Server的支持
这是一张从Linq in Action那本书里的截图,该图很好的在一个大的层次上揭示了Linq的视图。C#、vb.net等一系列.net语言在一些语言特性和Linq对语言的扩展上对Linq家族提供了支持。未来我们将会实现Linq in Everywhere,Linq将成为你的变成习惯。
C#对Linq的语言层面支持
使用
.OrderBy(book=>book.Price)
.Select(book=>new{Key=book.Title,Value=book.Price});
where book.Title.StartsWith("I")
orderby book.Price
select new { Key=book.Title,Value = book.Price};
{
return book.Title.StartsWith("I");
}).OrderBy<Book, float>(delegate(Book book)
{
return book.Price;
}).Select(delegate(Book book)
{
return new { Key = book.Title, Value = book.Price };
});
废话那么多了,还是来几个HelloWorld式的程序吧
HelloWorld Linq
(下面所有程序的Book就是本系列文章中第一篇所出现的Book类)
有一个Book集合,但是这个集合具体存储哪里我们并不清楚,也许在内存,也许在数据库,也许在XML存储,我们要做的就是把价格大于50的给揪出来,然后按照价格排序。
Linq to Objects(从内存中的集合里查找)
数据准备阶段
IList<Book> books = new List<Book> {
new Book { Title = "Inside COM", ISBN = "123-456-789",Price=20 },
new Book { Title = "Inside C#", ISBN = "123-356-d89",Price=100 },
new Book { Title = "Linq", ISBN = "123-d56-d89", Price = 120 }
};
where book.Price > 50
orderby book.Price
select new { Key = book.Title, Value = book.Price };
foreach (var item in result)
Console.WriteLine("Key:{0}-Value:{1}",item.Key,item.Value.ToString());
数据准备阶段
建立数据库表
输入数据
改写一下Book类,这个类是一个映射类,和数据库表做映射,更多内容后面会详细讲解
public class Book
{
/// <summary>
/// 图书名称
/// </summary>
[Column]
public string Title { get; set; }
/// <summary>
/// 单价
/// </summary>
[Column(DbType = "numeric(5, 2)")]
public float Price { get; set; }
/// <summary>
/// 作者
/// </summary>
[Column]
public string Author { get; set; }
/// <summary>
/// ISBN号
/// </summary>
[Column]
public string ISBN { get; set; }
}
var result = from book in db.GetTable<Book>()
where book.Price > 50
orderby book.Price
select new { Key = book.Title, Value = book.Price };
foreach (var item in result)
Console.WriteLine("Key:{0}-Value:{1}",item.Key,item.Value.ToString());
真所谓殊途同归啊,不管数据是如何存储的,查询的方式却99%一致。
总结
本篇旨在给大家一个对Linq的大局观认识,没有详细的深入,就算一个总览吧。精彩无需等待,祝大家编程愉快。