本专题概要:

  • 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 语句来返回序号为偶数的元素的实现代码如下:


   
   
  1. static void Main(string[] args) 
  2.         { 
  3.             #region Linq to objects 对比 
  4.             Console.WriteLine("使用老方法来对集合对象查询,查询结果为:"); 
  5.             OldQuery(); 
  6.             Console.WriteLine("使用Linq方法来对集合对象查询,查询结果为:"); 
  7.             LinqQuery(); 
  8.             Console.Read(); 
  9.       
  10.             #endregion 
  11.         } 
  12.        #region Linq to Objects对比 
  13.  
  14.         // 使用Linq 和使用Foreach语句的对比 
  15.  
  16.         // 1. 使用foreach返回集合中序号为偶数的元素 
  17.         private static void OldQuery() 
  18.         { 
  19.             // 初始化查询的数据 
  20.             List<string> collection = new List<string>(); 
  21.             for (int i = 0; i < 10; i++) 
  22.             { 
  23.                 collection.Add("A"+i.ToString()); 
  24.             } 
  25.            
  26.             // 创建保存查询结果的集合 
  27.             List<string> queryResults = new List<string>(); 
  28.             foreach (string s in collection) 
  29.             { 
  30.                 // 获取元素序号 
  31.                 int index = int.Parse(s.Substring(1)); 
  32.                 // 查询序号为偶数的元素 
  33.                 if (index % 2 == 0) 
  34.                 { 
  35.                     queryResults.Add(s); 
  36.                 } 
  37.             } 
  38.  
  39.             // 输出查询结果 
  40.             foreach (string s in queryResults) 
  41.             { 
  42.                 Console.WriteLine(s); 
  43.             } 
  44.         } 
  45.  
  46.         // 2. 使用Linq返回集合中序号为偶数的元素 
  47.         private static void LinqQuery() 
  48.         { 
  49.             // 初始化查询的数据 
  50.             List<string> collection = new List<string>(); 
  51.             for (int i = 0; i < 10; i++) 
  52.             { 
  53.                 collection.Add("A" + i.ToString()); 
  54.             } 
  55.  
  56.             // 创建查询表达式来获得序号为偶数的元素 
  57.             var queryResults = from s in collection 
  58.                                let index = int.Parse(s.Substring(1)) 
  59.                                where index % 2 == 0 
  60.                                select s; 
  61.             // 输出查询结果 
  62.             foreach (string s in queryResults) 
  63.             { 
  64.                 Console.WriteLine(s); 
  65.             } 
  66.         } 
  67.         #endregion 

 从上面的两个方法比较中可以看出使用Linq对集合进行查询时确实简单了许多,并且也容易添加筛选条件(只需要在Where 后面添加额外的筛选条件即可),运行结果当然也是我们期望的,下面也附上下运行结果截图:

 2.2 查询XML文件

之前我们大部分都会使用XPath来对XML文件进行查询,然而使用XPath来查询XML文件需要首先知道XML文件的具体结构,而Linq 查询表达式在查询XML数据的时,可以不需要知道XML文件结构,并且编码更加简单,容易添加判断的条件,下面就具体代码来说明使用Linq查询的好处(这里假设一个场景——有一个定义Persons的XML文件,现在我们要求查找出XML文件中Name节点为“李四”的元素):


   
   
  1. static void Main(string[] args) 
  2.         { 
  3.             #region Linq to XML 对比 
  4.             Console.WriteLine("使用XPath来对XML文件查询,查询结果为:"); 
  5.             OldLinqToXMLQuery(); 
  6.             Console.WriteLine("使用Linq方法来对XML文件查询,查询结果为:"); 
  7.             UsingLinqLinqtoXMLQuery(); 
  8.             Console.ReadKey(); 
  9.             #endregion 
  10.         }   
  11.   
  12.         #region Linq to XML 对比 
  13.      
  14.         // 初始化XML数据 
  15.         private static string xmlString =  
  16.             "<Persons>"
  17.             "<Person Id='1'>"
  18.             "<Name>张三</Name>"
  19.             "<Age>18</Age>"
  20.             "</Person>" + 
  21.             "<Person Id='2'>"
  22.             "<Name>李四</Name>"
  23.             "<Age>19</Age>"
  24.             "</Person>"
  25.              "<Person Id='3'>" + 
  26.             "<Name>王五</Name>" + 
  27.             "<Age>22</Age>" + 
  28.             "</Person>"
  29.             "</Persons>"
  30.  
  31.         // 使用XPath方式来对XML文件进行查询 
  32.         private static void OldLinqToXMLQuery() 
  33.         { 
  34.             // 导入XML文件 
  35.             XmlDocument xmlDoc = new XmlDocument(); 
  36.             xmlDoc.LoadXml(xmlString); 
  37.  
  38.             // 创建查询XML文件的XPath 
  39.             string xPath = "/Persons/Person"
  40.  
  41.             // 查询Person元素 
  42.             XmlNodeList querynodes = xmlDoc.SelectNodes(xPath); 
  43.             foreach (XmlNode node in querynodes) 
  44.             { 
  45.                 // 查询名字为李四的元素 
  46.                 foreach (XmlNode childnode in node.ChildNodes) 
  47.                 { 
  48.                     if (childnode.InnerXml == "李四"
  49.                     { 
  50.                         Console.WriteLine("姓名为: "+childnode.InnerXml + "  Id 为:" + node.Attributes["Id"].Value); 
  51.                     } 
  52.                 } 
  53.             } 
  54.  
  55.         } 
  56.  
  57.         // 使用Linq 来对XML文件进行查询 
  58.         private static void UsingLinqLinqtoXMLQuery() 
  59.         { 
  60.             // 导入XML 
  61.             XElement xmlDoc = XElement.Parse(xmlString); 
  62.  
  63.             // 创建查询,获取姓名为“李四”的元素 
  64.             var queryResults = from element in xmlDoc.Elements("Person"
  65.                                where element.Element("Name").Value == "李四" 
  66.                                select element; 
  67.             
  68.             // 输出查询结果 
  69.             foreach (var xele in queryResults) 
  70.             { 
  71.                 Console.WriteLine("姓名为: " + xele.Element("Name").Value + "  Id 为:" + xele.Attribute("Id").Value); 
  72.             } 
  73.         } 
  74.         #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来查找在文件目录中的是否存在特定的文件,具体代码如下:


   
   
  1. static void Main(string[] args) 
  2.      { 
  3.          string desktop = Environment.GetFolderPath(Environment.SpecialFolder.Desktop); 
  4.  
  5.          //FileQuery2(desktop); 
  6.          if (!string.IsNullOrEmpty(FileQuery())) 
  7.          { 
  8.              Console.WriteLine(FileQuery()); 
  9.          } 
  10.          else 
  11.          { 
  12.              Console.WriteLine("电脑桌面上不存在text.txt文件"); 
  13.          } 
  14.          Console.Read(); 
  15.      } 
  16.          // 使用Linq查询 
  17.      // 查询桌面是否存在text.txt文件 
  18.      private static string FileQuery() 
  19.      { 
  20.          string desktopdir = Environment.GetFolderPath(Environment.SpecialFolder.Desktop); 
  21.           
  22.          // 获得指定目录和子目录中的文件名 
  23.          string[] filenames = Directory.GetFiles(desktopdir, "*.*", SearchOption.AllDirectories); 
  24.          List<FileInfo> files = new List<FileInfo>(); 
  25.          foreach (var filename in filenames) 
  26.          { 
  27.              files.Add(new FileInfo(filename)); 
  28.          } 
  29.  
  30.          var results = from file in files 
  31.                        where file.Name == "text.txt" 
  32.                        select file; 
  33.  
  34.          // 输出查询结果 
  35.          StringBuilder queryResult = new StringBuilder(); 
  36.          foreach (var result in results) 
  37.          { 
  38.              queryResult.AppendLine("文件的路径为: " + result.FullName); 
  39.          } 
  40.  
  41.          return queryResult.ToString(); 
  42.      } 
  43.  
  44.      /// <summary> 
  45.      /// 使用递归来查找文件 
  46.      ///  查询桌面是否存在text.txt文件 
  47.      /// </summary> 
  48.      private static void FileQuery2(string path) 
  49.      { 
  50.          // 获得指定目录中的文件(包含子目录) 
  51.          string[] filenames = Directory.GetFiles(path); 
  52.          List<FileInfo> files = new List<FileInfo>(); 
  53.          foreach (var filename in filenames) 
  54.          { 
  55.              files.Add(new FileInfo(filename)); 
  56.          } 
  57.  
  58.          var results = from file in files 
  59.                        where file.Name == "text.txt" 
  60.                        select file; 
  61.  
  62.          // 输出查询结果 
  63.          StringBuilder queryResult = new StringBuilder(); 
  64.          foreach (var result in results) 
  65.          { 
  66.              Console.WriteLine("文件的路径为: " + result.FullName); 
  67.          } 
  68.  
  69.          // 获得所有子目录 
  70.          string[] dirs = Directory.GetDirectories(path); 
  71.          if (dirs.Length > 0) 
  72.          { 
  73.              foreach (string dir in dirs) 
  74.              { 
  75.                  FileQuery2(dir); 
  76.              } 
  77.          } 
  78.      } 

 运行结果为: 

 我的电脑桌面文件结果为:

 Desttop文件夹
    text.txt
    mytext文件夹
      text文件夹
            text.txt
        text.txt     

四、小结

 到这里本专题的内容就介绍完了, 本专题主要和大家简单分享了下我对Linq的认识,希望让大家对Linq有个大概的认识,在后面的深入理解Linq系列中将会和大家一起剖析下Linq的实现原理。并且这个专题也是C# 3特性中的最后一个特性的介绍了,在后面一个专题中将带来C# 4中一个最重要的特性——动态类型(dynamic )的引入