某日編程大師雲游到某處,見一剛畢業不久學過兩天C#和兩天SQL的coder在 那裡發牢騷,為啥我要寫這麼多for,這麼多if才能查詢出我需要的數據,為啥 我不能像SQL那樣,發送一條命令告訴數據庫我需要啥樣的數據,它就給我返回 來。
編程大師如是說:傻小子,像SQL那叫第四代編程語言,常存在於象 牙塔和研究所裡面的學究語言,還有個高雅的名字:函數編程。它只需要你告訴 它要什麼,而不需要告訴它怎麼做。而你使用的C#語言屬於命令式編程,你必須 像發送命令一樣一步步的告訴你的機器怎麼做。
發牢騷的coder回了一句 :不懂,我只是想不通,數據庫能做這樣的處理,為啥C#這麼牛的語言不能呢。編程大師心裡想著:這是不可能的事情,因為C#它是強類型語言,)*&) (&)*)()*&%&%&^(後面省去200字)。
天色還未晚,編 程大師就急匆匆的回家了,他心裡一直記著那位發牢騷的coder的話:為什麼不 能,為什麼不能。
晚上,編程大師做了一個夢,一個奇怪的夢,他的師 傅“白眉”只說了三個字母:DSL。
編程大師想著,DSL,領 域專用語言,師傅要對我說什麼呢,難道和今天我遇見的事有關?
上面 這段文字是一段調侃,調節一下氣氛,呵呵。
我覺得Linq就是一種DSL,在C#等常規語言上抽象起來的,面向數據處理領域的特定“語言”,當然,它的根基還是這些常規語言。
select,from,where,group等關鍵字 本來只是在SQL裡出現,現在把它們引入到C#這些常規編程語言中。
那C# 等是如何做到的呢?是在CLR底層支持的麼?不是。既然“編譯器” 可以將C#編譯成MSIL,那為什麼編譯不能干更多一點事情?將這些為了領域編程 而出現關鍵字編譯成原始語法。
下面還是從實例來說明吧:
我們有一個圖書類Book,先已經有 一個填充有數據的Book集合,我們需要從這個集合裡查找出單價小於50的書籍:
using System;
/**////
/// 圖書類
///
public class Book
{
/**////
/// 圖書名稱
///
public string Title { get; set; }
/**////
/// 單價
///
public float Price { get; set; }
/**////
/// 作者
///
public string Author { get; set; }
/**////
/// ISBN 號
///
public string ISBN { get; set; }
}
如是我可以寫這樣的代碼:
public static class Helper
{
public static IList<Book> SearchBookByPrice()
{
IList<Book> books = //..//初始化一個Book集合
IList<Book> results = new List<Book>();
foreach(Book book in books)
{
if(book.Price < 50)
{
results.Add(book);
}
}
return results;
}
}
現在是根 據單價查找,那如果我要按照書籍名稱查找或者按照作者查找怎麼辦?那只有重 寫這個方法了。但是你想想,我們的查找條件到最後只不過是一個true或者 false,只要if()裡面的表達式為true我們就將其添加到返回結果的集合中,我 才不管裡面的表達式詳細的是什麼呢,ok,那這樣我們就可以進一步改進這個方 法了:
public static class Helper
{
public delegate bool Condtion(Book book);
public static IList<Book> SearchBook(Condtion condition)
{
IList<Book> books = //..//初始化一個Book集合
IList < Book > results = new List<Book>();
foreach (Book book in books)
{
if (condition(book))
{
results.Add (book);
}
}
return results;
}
}
看看我們如何調用改進後的方法:
public bool ConditionTitle(Book book)
{
return book.Title == "yuyi";
}
IList<Book> results = Helper.SearchBook(new Condition (ConditionTitle));
我們將查詢條件使用委托解決了,只要傳遞 一個接收Book作為參數,返回bool值的方法進去就可以查詢滿足條件的書籍了,但是,為了這個委托,我們還得先定義一個新方法,然後。。。。太麻煩了,為 此C# 2.0為我們提供了匿名方法,專門針對這些只有“一句話方法” :
IList<Book> results = Helper.SearchBook(delegate(Book book) { return book.Title == "yuyi"; });
代碼是減少不 少,可這種寫法還是不“人性化”,這還是一種人向計算機妥協的結 果,才產生了這種怪異的寫法,如是C# 3.0給我們提供了Lambda表達 式:
IList<Book> results = Helper.SearchBook(book => book.Title == "yuyi");
代碼更短了,寫法也越來越向人類 語言靠近了(這也許就是計算機語言的發展歷史,隨著計算機越來越智能,總有 一天必會是計算機向人類妥協)。
不過這裡還有一點不爽,每一次調用這 個查找方法都要帶Helper,要是IList自己就這個方法該多好。這個想法很好,C# 3.0裡還為我們提供了擴展方法:
public static class Helper
{
public delegate bool Condtion(Book book);
public static IList<Book> Where(this IList<Book> books,Condtion condition)
{
IList < Book > results = new List<Book>();
foreach (Book book in books)
{
if (condition(book))
{
results.Add (book);
}
}
return results;
}
}
仔細比較一下這個實現與剛才的實現有何 不同(我們還給它起了一個更好聽的名字Where,是不是和SQL更像了),現在我們 可以這樣調用了:
IList<Book> results = books.Where(book => book.Title == "yuyi");
Books是一個IList,這行代 碼是多麼的自然而優雅。依葫蘆畫瓢,我們可以到處這樣書寫代碼了,不僅僅可 以查找書籍,還可以查找帳戶,一切處理集合查找的方法我都希望這樣做,終於 有一天你厭煩了,查找書,查找帳戶,等等,他們之間沒有什麼差異,為什麼我 們要做這麼多重復的工作呢,所有的IList都繼承自IEnumerable,我們為啥不給 IEnumerable添加一個Where方法,這樣我們不就一勞永逸了麼,現在該是泛型施 展才華的地方了:
public static class Helper
{
public delegate bool Condtion<T>(T t);
public static IEnumerable<T> FindBy<T>(this IEnumerable<T> items, Condtion<T> condition)
{
foreach (T t in items)
{
if (condition(t))
{
//C# 2.0裡出現的一個關鍵字,返回一個迭代器
yield return t;
}
}
}
}
現在,不管是IList還是IList都可以使用 這個Where方法了但是做集合操作的時候我們不僅僅需要Where,還需要OrderBy ,Group等等,我想把所有的SQL能干的都移植過來。當然微軟也意識到了這點,如是在.net 3.5裡,微軟發布了我們夢寐以求的Linq,將查詢集成到語言裡面來 。它給IEnumerable添加了很多擴展方法,這樣你可以很自然的去調用。你可以 使用Reflector打開System.Core.dll,打開System.Linq命名空間,在這個命名 空間裡有一個Enumerable類,這裡面就是微軟為我們添加的擴展方法,看看,是 不是SQL裡所有的東西都可以在這裡找到了。
好了,就此擱筆吧,這一篇 作為我的走進Linq系列的開篇,在接下來我會為你把Linq大卸八塊。