# [C# 基礎知識系列]專題十六:Linq介紹
**本專題概要:**
* **Linq是什么**
* **使用Linq的好處在哪里**
* **Linq的實際操作例子——使用Linq遍歷文件目錄**
* **小結**
**引言:**
終于到了C# 3中最重要特性的介紹了,可以說之前所有介紹的特性都是為了Linq而做準備的,然而要想深入理解Linq并不是這個專題可以介紹完的,所以我打算這個專題將對Linq做一個簡單的介紹,對于Linq的深入理解我將會后面單獨作為一個系列要和大家分享下。
**一、Linq是什么?**
Linq也就是Language Integrated Query的縮寫,即語言集成查詢,是微軟在.Net 3.5中提出的一項新技術, Linq主要包含4個組件——Linq to Objects、Linq to XML、Linq to DataSet 和Linq to SQL。在這里不會具體介紹這4個組件的內容,只會給出一個大致的介紹, 下面先看看Linq的一個架構圖,希望可以讓大家可以對Linq有一個全面的認識:

下面簡單介紹下四個組件:
* Linq to SQL 組件——可以查詢基于關系數據的數據(微軟本身只是實現了對SQL Server的查詢,可以對數據庫中的數據進行查詢,修改,插入,刪除,排序等操作
* Linq to Dataset組件——可以查詢DasaSet對象中的數據,并對數據進行增刪改查的操作
* Linq to Objects組件——可以查詢IEnumberable 或IEnumberable<T>集合
* Linq to XML 組件——可以差選和操作XML文件,比Xpath操作XML更加方便
**二、使用Linq的好處在哪里**
第一部分中說到Linq中包括四個組件,分別是對不同數據進行增刪改查的一些操作,然而以前也是有相關技術來對這些數據進行操作,(例如,對數據庫的操作,之前有Ado.Net 對其進行支持,對XML的操作,之前也可以XPath來操作XML文件等), 此時應該大家都會有個疑問的——為什么以前都有相關的技術對其進行支持,那我們為什么還需要Linq呢?對于這個疑問答案很簡單,Linq 使操作這些數據源更加簡單,方便和易于理解,之前的技術操作起來過于繁瑣,所以微軟也有上進心啊,希望可以做的更好啊,所以就在C# 3中提出了Linq來方便大家操作這些數據源,下面通過對比來說明Linq是如何簡單方便:
**2.1 查詢集合中的數據**
之前我們查詢集合中的數據一般會使用for或foreach語句來進行查詢,而Linq 使用查詢表達式來進行查詢,Linq 表達式比之前用for或forach的方式更加簡潔,比較容易添加篩選條件,下面就具體看看兩者方式的比較代碼(我們這里假設一個場景——**返回集合中序號為偶數的元素**)
使用foreach 語句來返回序號為偶數的元素的實現代碼如下:
```
static void Main(string[] args)
{
#region Linq to objects 對比
Console.WriteLine("使用老方法來對集合對象查詢,查詢結果為:");
OldQuery();
Console.WriteLine("使用Linq方法來對集合對象查詢,查詢結果為:");
LinqQuery();
Console.Read();
#endregion
}
#region Linq to Objects對比
// 使用Linq 和使用Foreach語句的對比
// 1\. 使用foreach返回集合中序號為偶數的元素
private static void OldQuery()
{
// 初始化查詢的數據
List<string> collection = new List<string>();
for (int i = 0; i < 10; i++)
{
collection.Add("A"+i.ToString());
}
// 創建保存查詢結果的集合
List<string> queryResults = new List<string>();
foreach (string s in collection)
{
// 獲取元素序號
int index = int.Parse(s.Substring(1));
// 查詢序號為偶數的元素
if (index % 2 == 0)
{
queryResults.Add(s);
}
}
// 輸出查詢結果
foreach (string s in queryResults)
{
Console.WriteLine(s);
}
}
// 2\. 使用Linq返回集合中序號為偶數的元素
private static void LinqQuery()
{
// 初始化查詢的數據
List<string> collection = new List<string>();
for (int i = 0; i < 10; i++)
{
collection.Add("A" + i.ToString());
}
// 創建查詢表達式來獲得序號為偶數的元素
var queryResults = from s in collection
let index = int.Parse(s.Substring(1))
where index % 2 == 0
select s;
// 輸出查詢結果
foreach (string s in queryResults)
{
Console.WriteLine(s);
}
}
#endregion
```
從上面的兩個方法比較中可以看出使用Linq對集合進行查詢時確實簡單了許多,并且也容易添加篩選條件(只需要在Where 后面添加額外的篩選條件即可),運行結果當然也是我們期望的,下面也附上下運行結果截圖:

**2.2 查詢XML文件**
之前我們大部分都會使用XPath來對XML文件進行查詢,然而使用XPath來查詢XML文件需要首先知道XML文件的具體結構,而Linq 查詢表達式在查詢XML數據的時,可以不需要知道XML文件結構,并且編碼更加簡單,容易添加判斷的條件,下面就具體代碼來說明使用Linq查詢的好處(這里假設一個場景——有一個定義Persons的XML文件,現在我們要求查找出XML文件中Name節點為“李四”的元素):
```
static void Main(string[] args)
{
#region Linq to XML 對比
Console.WriteLine("使用XPath來對XML文件查詢,查詢結果為:");
OldLinqToXMLQuery();
Console.WriteLine("使用Linq方法來對XML文件查詢,查詢結果為:");
UsingLinqLinqtoXMLQuery();
Console.ReadKey();
#endregion
}
#region Linq to XML 對比
// 初始化XML數據
private static string xmlString =
"<Persons>"+
"<Person Id='1'>"+
"<Name>張三</Name>"+
"<Age>18</Age>"+
"</Person>" +
"<Person Id='2'>"+
"<Name>李四</Name>"+
"<Age>19</Age>"+
"</Person>"+
"<Person Id='3'>" +
"<Name>王五</Name>" +
"<Age>22</Age>" +
"</Person>"+
"</Persons>";
// 使用XPath方式來對XML文件進行查詢
private static void OldLinqToXMLQuery()
{
// 導入XML文件
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xmlString);
// 創建查詢XML文件的XPath
string xPath = "/Persons/Person";
// 查詢Person元素
XmlNodeList querynodes = xmlDoc.SelectNodes(xPath);
foreach (XmlNode node in querynodes)
{
// 查詢名字為李四的元素
foreach (XmlNode childnode in node.ChildNodes)
{
if (childnode.InnerXml == "李四")
{
Console.WriteLine("姓名為: "+childnode.InnerXml + " Id 為:" + node.Attributes["Id"].Value);
}
}
}
}
// 使用Linq 來對XML文件進行查詢
private static void UsingLinqLinqtoXMLQuery()
{
// 導入XML
XElement xmlDoc = XElement.Parse(xmlString);
// 創建查詢,獲取姓名為“李四”的元素
var queryResults = from element in xmlDoc.Elements("Person")
where element.Element("Name").Value == "李四"
select element;
// 輸出查詢結果
foreach (var xele in queryResults)
{
Console.WriteLine("姓名為: " + xele.Element("Name").Value + " Id 為:" + xele.Attribute("Id").Value);
}
}
#endregion
```
使用XPath方式來查詢XML文件時,首先需要知道XML文件的具體結構(代碼中需要指定XPath為"/Persons/Person", 這就說明必須知道XML的組成結構了),然而使用Linq方式卻不需要知道XML文檔結構,并且從代碼書寫的量上也可以看出使用Linq方式的簡潔性,下面附上運行結果截圖:

對于Linq to SQL 和Linq to DataSet的例子,我這里就不一一給出了,從上面的兩個例子已經完全可以說明使用Linq的好處了,下面總結我理解的好處有:
* Linq 查詢表達式使用上更加簡單,而且也易于理解(沒有接觸過Linq的人也可以大致猜出代碼的意圖是什么的)
* Linq 提供了更多的功能,我們可以查詢、排序、分組、增加和刪除等操作數據的大部分功能
* 可以使用Linq處理多種數據源,也可以為特定的數據源定義自己的Linq實現(這點將會在深入理解Linq中與大家相信介紹)
**三、Linq的實際操作例子——使用Linq遍歷文件目錄**
通過前面兩部分大家大致可以知道Linq的強大了吧,這部分就具體給出一個例子來看看使用Linq具體可以做些什么事情的? 如果大家做一個文件管理系統的時候,大家都需要遍歷文件目錄的吧,下面就使用Linq來查找在文件目錄中的是否存在特定的文件,具體代碼如下:
```
static void Main(string[] args)
{
string desktop = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
//FileQuery2(desktop);
if (!string.IsNullOrEmpty(FileQuery()))
{
Console.WriteLine(FileQuery());
}
else
{
Console.WriteLine("電腦桌面上不存在text.txt文件");
}
Console.Read();
}
// 使用Linq查詢
// 查詢桌面是否存在text.txt文件
private static string FileQuery()
{
string desktopdir = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
// 獲得指定目錄和子目錄中的文件名
string[] filenames = Directory.GetFiles(desktopdir, "*.*", SearchOption.AllDirectories);
List<FileInfo> files = new List<FileInfo>();
foreach (var filename in filenames)
{
files.Add(new FileInfo(filename));
}
var results = from file in files
where file.Name == "text.txt"
select file;
// 輸出查詢結果
StringBuilder queryResult = new StringBuilder();
foreach (var result in results)
{
queryResult.AppendLine("文件的路徑為: " + result.FullName);
}
return queryResult.ToString();
}
/// <summary>
/// 使用遞歸來查找文件
/// 查詢桌面是否存在text.txt文件
/// </summary>
private static void FileQuery2(string path)
{
// 獲得指定目錄中的文件(包含子目錄)
string[] filenames = Directory.GetFiles(path);
List<FileInfo> files = new List<FileInfo>();
foreach (var filename in filenames)
{
files.Add(new FileInfo(filename));
}
var results = from file in files
where file.Name == "text.txt"
select file;
// 輸出查詢結果
StringBuilder queryResult = new StringBuilder();
foreach (var result in results)
{
Console.WriteLine("文件的路徑為: " + result.FullName);
}
// 獲得所有子目錄
string[] dirs = Directory.GetDirectories(path);
if (dirs.Length > 0)
{
foreach (string dir in dirs)
{
FileQuery2(dir);
}
}
}
```
運行結果為:

我的電腦桌面文件結果為:
**四、小結**
到這里本專題的內容就介紹完了, 本專題主要和大家簡單分享了下我對Linq的認識,希望讓大家對Linq有個大概的認識,在后面的深入理解Linq系列中將會和大家一起剖析下Linq的實現原理。并且這個專題也是C# 3特性中的最后一個特性的介紹了,在后面一個專題中將帶來C# 4中一個最重要的特性——動態類型(**dynamic** )的引入
專題中的源碼: [http://files.cnblogs.com/zhili/LinqDemo.zip](http://files.cnblogs.com/zhili/LinqDemo.zip)
- C# 基礎知識系列
- C# 基礎知識系列 專題一:深入解析委托——C#中為什么要引入委托
- C# 基礎知識系列 專題二:委托的本質論
- C# 基礎知識系列 專題三:如何用委托包裝多個方法——委托鏈
- C# 基礎知識系列 專題四:事件揭秘
- C# 基礎知識系列 專題五:當點擊按鈕時觸發Click事件背后發生的事情
- C# 基礎知識系列 專題六:泛型基礎篇——為什么引入泛型
- C# 基礎知識系列 專題七: 泛型深入理解(一)
- C# 基礎知識系列 專題八: 深入理解泛型(二)
- C# 基礎知識系列 專題九: 深入理解泛型可變性
- C#基礎知識系列 專題十:全面解析可空類型
- C# 基礎知識系列 專題十一:匿名方法解析
- C#基礎知識系列 專題十二:迭代器
- C#基礎知識 專題十三:全面解析對象集合初始化器、匿名類型和隱式類型
- C# 基礎知識系列 專題十四:深入理解Lambda表達式
- C# 基礎知識系列 專題十五:全面解析擴展方法
- C# 基礎知識系列 專題十六:Linq介紹
- C#基礎知識系列 專題十七:深入理解動態類型
- 你必須知道的異步編程 C# 5.0 新特性——Async和Await使異步編程更簡單
- 全面解析C#中參數傳遞
- C#基礎知識系列 全面解析C#中靜態與非靜態
- C# 基礎知識系列 C#中易混淆的知識點
- C#進階系列
- C#進階系列 專題一:深入解析深拷貝和淺拷貝
- C#進階系列 專題二:你知道Dictionary查找速度為什么快嗎?
- C# 開發技巧系列
- C# 開發技巧系列 使用C#操作Word和Excel程序
- C# 開發技巧系列 使用C#操作幻燈片
- C# 開發技巧系列 如何動態設置屏幕分辨率
- C# 開發技巧系列 C#如何實現圖片查看器
- C# 開發技巧 如何防止程序多次運行
- C# 開發技巧 實現屬于自己的截圖工具
- C# 開發技巧 如何使不符合要求的元素等于離它最近的一個元素
- C# 線程處理系列
- C# 線程處理系列 專題一:線程基礎
- C# 線程處理系列 專題二:線程池中的工作者線程
- C# 線程處理系列 專題三:線程池中的I/O線程
- C# 線程處理系列 專題四:線程同步
- C# 線程處理系列 專題五:線程同步——事件構造
- C# 線程處理系列 專題六:線程同步——信號量和互斥體
- C# 多線程處理系列專題七——對多線程的補充
- C#網絡編程系列
- C# 網絡編程系列 專題一:網絡協議簡介
- C# 網絡編程系列 專題二:HTTP協議詳解
- C# 網絡編程系列 專題三:自定義Web服務器
- C# 網絡編程系列 專題四:自定義Web瀏覽器
- C# 網絡編程系列 專題五:TCP編程
- C# 網絡編程系列 專題六:UDP編程
- C# 網絡編程系列 專題七:UDP編程補充——UDP廣播程序的實現
- C# 網絡編程系列 專題八:P2P編程
- C# 網絡編程系列 專題九:實現類似QQ的即時通信程序
- C# 網絡編程系列 專題十:實現簡單的郵件收發器
- C# 網絡編程系列 專題十一:實現一個基于FTP協議的程序——文件上傳下載器
- C# 網絡編程系列 專題十二:實現一個簡單的FTP服務器
- C# 互操作性入門系列
- C# 互操作性入門系列(一):C#中互操作性介紹
- C# 互操作性入門系列(二):使用平臺調用調用Win32 函數
- C# 互操作性入門系列(三):平臺調用中的數據封送處理
- C# 互操作性入門系列(四):在C# 中調用COM組件
- CLR
- 談談: String 和StringBuilder區別和選擇
- 談談:程序集加載和反射
- 利用反射獲得委托和事件以及創建委托實例和添加事件處理程序
- 談談:.Net中的序列化和反序列化
- C#設計模式
- UML類圖符號 各種關系說明以及舉例
- C#設計模式(1)——單例模式
- C#設計模式(2)——簡單工廠模式
- C#設計模式(3)——工廠方法模式
- C#設計模式(4)——抽象工廠模式
- C#設計模式(5)——建造者模式(Builder Pattern)
- C#設計模式(6)——原型模式(Prototype Pattern)
- C#設計模式(7)——適配器模式(Adapter Pattern)
- C#設計模式(8)——橋接模式(Bridge Pattern)
- C#設計模式(9)——裝飾者模式(Decorator Pattern)
- C#設計模式(10)——組合模式(Composite Pattern)
- C#設計模式(11)——外觀模式(Facade Pattern)
- C#設計模式(12)——享元模式(Flyweight Pattern)
- C#設計模式(13)——代理模式(Proxy Pattern)
- C#設計模式(14)——模板方法模式(Template Method)
- C#設計模式(15)——命令模式(Command Pattern)
- C#設計模式(16)——迭代器模式(Iterator Pattern)
- C#設計模式(17)——觀察者模式(Observer Pattern)
- C#設計模式(18)——中介者模式(Mediator Pattern)
- C#設計模式(19)——狀態者模式(State Pattern)
- C#設計模式(20)——策略者模式(Stragety Pattern)
- C#設計模式(21)——責任鏈模式
- C#設計模式(22)——訪問者模式(Vistor Pattern)
- C#設計模式(23)——備忘錄模式(Memento Pattern)
- C#設計模式總結
- WPF快速入門系列
- WPF快速入門系列(1)——WPF布局概覽
- WPF快速入門系列(2)——深入解析依賴屬性
- WPF快速入門系列(3)——深入解析WPF事件機制
- WPF快速入門系列(4)——深入解析WPF綁定
- WPF快速入門系列(5)——深入解析WPF命令
- WPF快速入門系列(6)——WPF資源和樣式
- WPF快速入門系列(7)——深入解析WPF模板
- WPF快速入門系列(8)——MVVM快速入門
- WPF快速入門系列(9)——WPF任務管理工具實現
- ASP.NET 開發
- ASP.NET 開發必備知識點(1):如何讓Asp.net網站運行在自定義的Web服務器上
- ASP.NET 開發必備知識點(2):那些年追過的ASP.NET權限管理
- ASP.NET中實現回調
- 跟我一起學WCF
- 跟我一起學WCF(1)——MSMQ消息隊列
- 跟我一起學WCF(2)——利用.NET Remoting技術開發分布式應用
- 跟我一起學WCF(3)——利用Web Services開發分布式應用
- 跟我一起學WCF(3)——利用Web Services開發分布式應用
- 跟我一起學WCF(4)——第一個WCF程序
- 跟我一起學WCF(5)——深入解析服務契約 上篇
- 跟我一起學WCF(6)——深入解析服務契約 下篇
- 跟我一起學WCF(7)——WCF數據契約與序列化詳解
- 跟我一起學WCF(8)——WCF中Session、實例管理詳解
- 跟我一起學WCF(9)——WCF回調操作的實現
- 跟我一起學WCF(10)——WCF中事務處理
- 跟我一起學WCF(11)——WCF中隊列服務詳解
- 跟我一起學WCF(12)——WCF中Rest服務入門
- 跟我一起學WCF(13)——WCF系列總結
- .NET領域驅動設計實戰系列
- .NET領域驅動設計實戰系列 專題一:前期準備之EF CodeFirst
- .NET領域驅動設計實戰系列 專題二:結合領域驅動設計的面向服務架構來搭建網上書店
- .NET領域驅動設計實戰系列 專題三:前期準備之規約模式(Specification Pattern)
- .NET領域驅動設計實戰系列 專題四:前期準備之工作單元模式(Unit Of Work)
- .NET領域驅動設計實戰系列 專題五:網上書店規約模式、工作單元模式的引入以及購物車的實現
- .NET領域驅動設計實戰系列 專題六:DDD實踐案例:網上書店訂單功能的實現
- .NET領域驅動設計實戰系列 專題七:DDD實踐案例:引入事件驅動與中間件機制來實現后臺管理功能
- .NET領域驅動設計實戰系列 專題八:DDD案例:網上書店分布式消息隊列和分布式緩存的實現
- .NET領域驅動設計實戰系列 專題九:DDD案例:網上書店AOP和站點地圖的實現
- .NET領域驅動設計實戰系列 專題十:DDD擴展內容:全面剖析CQRS模式實現
- .NET領域驅動設計實戰系列 專題十一:.NET 領域驅動設計實戰系列總結