本系列文章
走进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的大局观认识,没有详细的深入,就算一个总览吧。精彩无需等待,祝大家编程愉快。