[C# 基础知识系列]专题十六:Linq介绍

转自http://www.cnblogs.com/zhili/archive/2012/12/24/Linq.html

本专题概要:

  • 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);
                }
            }
        }

运行结果为:

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

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

四、小结

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

专题中的源码: http://files.cnblogs.com/zhili/LinqDemo.zip

时间: 2024-11-01 01:23:53

[C# 基础知识系列]专题十六:Linq介绍的相关文章

[C#基础知识系列]专题十:全面解析可空类型[转]

原文链接 主要内容: 1:空合并操作符(?? 操作符) ??操作符也就是"空合并操作符",它代表的意思是两个操作数,如果左边的数不为null时,就返回左边的数,如果左边的数为null,就返回右边的数,这个操作符可以用于可空类型,也可以用于引用类型,但是不能用于值类型(之所以不能应用值类型(这里除了可空类型),因为??运算符要对左边的数与null进行比较,然而值类型,不能与null类型比较,所以就不支持??运算符),下面用一个例子来掩饰下??运算符的使用(??这个运算符可以方便我们设置默

[C# 基础知识系列]专题一:深入解析委托——C#中为什么要引入委托

转自http://www.cnblogs.com/zhili/archive/2012/10/22/Delegate.html 引言: 对于一些刚接触C# 不久的朋友可能会对C#中一些基本特性理解的不是很深,然而这些知识也是面试时面试官经常会问到的问题,所以我觉得有必要和一些接触C#不久的朋友分享下关于C#基础知识的文章,所以有了这个系列,希望通过这个系列让朋友对C#的基础知识理解能够更进一步.然而委托又是C#基础知识中比较重要的一点,基本上后面的特性都和委托有点关系,所以这里就和大家先说说委托

[C# 基础知识系列]专题四:事件揭秘

转自http://www.cnblogs.com/zhili/archive/2012/10/27/Event.html 引言: 前面几个专题对委托进行了详细的介绍的,然后我们在编写代码过程中经常会听到“事件”这个概念的,尤其是写UI的时候,当我们点击一个按钮后VS就会自动帮我们生成一些后台的代码,然后我们就只需要在Click方法里面写代码就可以,所以可能有些刚接触C#的朋友就觉得这样很理所当然的,也没有去思考这是为什么的,为什么点击下事件就会触发我们在Click方法里面写的代码呢?事件到底扮演

[C# 网络编程系列]专题十:实现简单的邮件收发器

转自:http://www.cnblogs.com/zhili/archive/2012/09/24/2689892.html 引言: 在我们的平常工作中,邮件的发送和接收应该是我们经常要使用到的功能的.因此知道电子邮件的应用程序的原理也是非常有必要的,在这一个专题中将介绍电子邮件应用程序的原理.电子邮件应用程序中涉及的协议和实现一个简答的电子邮件收发器程序. 一.邮件应用程序基本知识 1.1 电子邮件原理及相关协议 说到电子邮件的原理,其实和我们现实生活中寄邮件和寄包裹是一样的原理的.就让我们

quick-cocos2d-x 学习系列之十六 塔防完结

quick-cocos2d-x 学习系列之十六 塔防完结 1.  math2d.lua文件 该文件实现了常用的数学函数. Dist函数实现两点的距离. radians4point求两点的夹角(弧度) pointAtCircle求圆上一个点的位置 pointAtLineToPoint求线段上与指定点距离最近的点 degrees2radians角度转换为弧度 radians2degrees弧度转换为角度 2.  utils.lua文件 2.1         drawCircle 返回newCirc

线程基础知识系列(三)线程的同步

本文是系列的第三篇,前面2篇,主要是针对单个线程如何管理,启动等,没有过多涉及多个线程是如何协同工作的. 线程基础知识系列(二)线程的管理 :线程的状态,控制,休眠,Interrupt,yield等 线程基础知识系列(一)线程的创建和启动  :线程的创建和启动,join(),daemon线程,Callable任务. 本文的主要内容 何谓线程安全? 何谓共享可变变量? 认识synchronized关键字 认识Lock synchronized vs Lock 1.何谓线程安全 多线程是把双刃剑,带

C++语言笔记系列之十六——赋值兼容规则&amp;多继承的二义性

1.赋值兼容规则 (1)派生类对象可以给基类对象赋值,这种情况下派生类对象将从基类继承的成员的值赋值给一个基类对象:但是不允许将一个基类的对象赋值给一个派生类. (2)可以将派生类对象的地址赋给基类指针,使基类指针指向派生类对象,通过基类指针引用成员时只可以引用派生类从基类继承而来的成员,而不允许引用派生类的新成员. (3)引用与指针相同. 2.多继承 (1)一个派生类从两个以上的基类中去继承. (2)说明: class 派生类名:继承方式 基类1, 继承方式 基类2,...... {派生类成员

线程基础知识系列(二)线程的管理

本篇是线程基础知识系列的第二篇,主要简单江夏线程管理相关知识点. 线程基础知识系列(一)线程的创建和启动:说明了线程的2种创建和启动,join(),daemon线程,Callable 任务. 本文的主要内容 线程的状态 线程的优先级 sleep vs wait 线程的流程控制 Interrupt yield让出你的CPU 1.线程的状态 以<线程基础知识系列(一)线程的创建和启动>这张图,是程序的运行时线程信息截图.有main线程,user Threads,daemon Threads.现在咱

开发指南专题十六:JEECG微云快速开发平台Excel导出

Ladda 应用提交表单的时候显示loading加载中 包括不同位置,不同效果 不同大小,位置,效果,进度条等 演示 XML/HTML Code <article class="examples" style="margin-top:0px;"> <section class="button-demo"> <h3>expand-left</h3> <button class="lad