C# LINQ学习笔记一:走进LINQ的世界

摘要:
LINQ简介:语言集成查询是VisualStudio2008和.NETFramework3.5版中引入的一项创新功能。LINQ通过提供一种跨数据源和数据格式使用数据的一致模型,简化了这一情况。在LINQ查询中,始终会用到对象。在LINQ中,查询的执行与查询本身截然不同。可查询类型不需要进行修改或特殊处理就可以用作LINQ数据源。例如,LINQtoXML将XML文档加载到可查询的XElement类型中。

本笔记摘抄自:https://www.cnblogs.com/liqingwen/p/5832322.html,记录一下学习过程以备后续查用。

LINQ 简介:

语言集成查询(LINQ)是Visual Studio 2008和.NET Framework 3.5版中引入的一项创新功能。

传统上,针对数据的查询都是以简单的字符串表示,而没有编译时类型检查或IntelliSense支持。此外,您还必须针对以下各种数据源学习一种不同的查询

语言:SQL数据库、XML文档、各种Web服务等。通过LINQ,可以使用语言关键字和熟悉的运算符针对强类型化对象集合编写查询。

C# LINQ学习笔记一:走进LINQ的世界第1张

在Visual Studio中,可以为以下数据源编写LINQ查询:SQL Server数据库、XML文档、ADO.NET数据集以及支持IEnumerable或泛型IEnumerable<T>

接口的任意对象集合,使用要求:项目 ≥ .NET Framework 3.5。

一、LINQ查询

查询是一种从数据源检索数据的表达式。随着时间的推移,人们已经为各种数据源开发了不同的语言。例如,用于关系数据库的SQL和用于XML的XQuery。

因此,开发人员不得不针对他们必须支持的每种数据源或数据格式而学习新的查询语言。LINQ通过提供一种跨数据源和数据格式使用数据的一致模型,简化

了这一情况。在LINQ查询中,始终会用到对象。可以使用相同的编码模式来查询和转换XML文档、SQL数据库、ADO.NET数据集、.NET集合中的数据以及

对其有LINQ提供程序可用的任何其他格式的数据。

1.1查询操作的三个部分

操作三部曲:①取数据源 ②创建查询 ③执行查询

下面代码演示LINQ to OBJECT:

C# LINQ学习笔记一:走进LINQ的世界第2张C# LINQ学习笔记一:走进LINQ的世界第3张
    classProgram
    {
        static void Main(string[] args)
        {
            #region LINQ to OBJECT
            //查询三部曲:1、获取数据源
            var nums = new int[7] { 0, 1, 2, 3, 4, 5, 6};

            //查询三部曲:2、创建查询
            var query =
                from num innums
                where (num % 2) == 0
                selectnum;

            //查询三部曲:3、执行查询
            foreach (var num inquery)
            {
                Console.Write($"{num} ");
            }

            Console.Read();
            #endregion}
    }
View Code

运行结果如下:

C# LINQ学习笔记一:走进LINQ的世界第4张

下图显示了完整的查询操作。在LINQ中,查询的执行与查询本身截然不同。换句话说,查询本身指的是只创建查询变量,不检索任何数据。

C# LINQ学习笔记一:走进LINQ的世界第5张

1.2数据源

在上一个示例中(LINQ to OBJECT),由于数据源是数组,因此它隐式支持泛型IEnumerable<T>(可枚举)接口。支持IEnumerable<T>或派生接口(如

泛型IQueryable<T>)的类型称为可查询类型。

可查询类型不需要进行修改或特殊处理就可以用作LINQ数据源。如果源数据还没有作为可查询类型出现在内存中,则LINQ提供程序必须以此方式表示源数

据。例如,LINQ to XML将XML文档加载到可查询的XElement类型中。

下面代码演示LINQ to XML:

创建一个Test.xml文件,放在主目录下。

C# LINQ学习笔记一:走进LINQ的世界第2张C# LINQ学习笔记一:走进LINQ的世界第7张
<DocumentElement>
  <Category>
    <MO_NO>MOA1911070001</MO_NO>
    <MRP_NO>8198712090963008</MRP_NO>
    <QTY>1.00000000</QTY>
    <BIL_NO>MPA19110701</BIL_NO>
  </Category>
  <Category>
    <MO_NO>MOA1911070002</MO_NO>
    <MRP_NO>8193000000003172</MRP_NO>
    <QTY>1.00000000</QTY>
    <BIL_NO>MPA19110702</BIL_NO>
  </Category>
  <Category>
    <MO_NO>MOA1911070003</MO_NO>
    <MRP_NO>8193002043133003</MRP_NO>
    <QTY>1.00000000</QTY>
    <BIL_NO>MPA19110702</BIL_NO>
  </Category>
  <Category>
    <MO_NO>MOA1911070004</MO_NO>
    <MRP_NO>8193002043133004</MRP_NO>
    <QTY>1.00000000</QTY>
    <BIL_NO>MPA19110702</BIL_NO>
  </Category>
  <Category>
    <MO_NO>MOA1911070005</MO_NO>
    <MRP_NO>8193002043133005</MRP_NO>
    <QTY>1.00000000</QTY>
    <BIL_NO>MPA19110702</BIL_NO>
  </Category>
  <Category>
    <MO_NO>MOA1911070006</MO_NO>
    <MRP_NO>8198922092971001</MRP_NO>
    <QTY>1.00000000</QTY>
    <BIL_NO>MPA19110703</BIL_NO>
  </Category>
  <Category>
    <MO_NO>MOA1911070007</MO_NO>
    <MRP_NO>8198922092971002</MRP_NO>
    <QTY>1.00000000</QTY>
    <BIL_NO>MPA19110703</BIL_NO>
  </Category>
  <Category>
    <MO_NO>MOA1911070008</MO_NO>
    <MRP_NO>8198922092971010</MRP_NO>
    <QTY>1.00000000</QTY>
    <BIL_NO>MPA19110703</BIL_NO>
  </Category>
  <Category>
    <MO_NO>MOA1911070009</MO_NO>
    <MRP_NO>8198922092971200</MRP_NO>
    <QTY>1.00000000</QTY>
    <BIL_NO>MPA19110703</BIL_NO>
  </Category>
  <Category>
    <MO_NO>MOA1911070010</MO_NO>
    <MRP_NO>8199862094443008</MRP_NO>
    <QTY>1.00000000</QTY>
    <BIL_NO>MPA19110704</BIL_NO>
  </Category>
</DocumentElement>
View Code
C# LINQ学习笔记一:走进LINQ的世界第2张C# LINQ学习笔记一:走进LINQ的世界第9张
    classProgram
    {
        static void Main(string[] args)
        {
            #region LINQ to XML
            var xe = XElement.Load(@"....Test.xml");
            var query =
                from item in xe.Descendants("Category")
                selectitem;
            foreach (var item inquery)
            {
                Console.WriteLine($"MO_NO={item.Element("MO_NO").Value}");
            }
            Console.Read();
            #endregion}
    }
View Code

运行结果如下:

C# LINQ学习笔记一:走进LINQ的世界第10张

LINQ to SQL中,首先需要生成对象模型映射到关系数据库,然后针对这些对象编写查询,由LINQ to SQL在运行时处理与数据库的通信。

准备一:下文中用到的Northwind数据库,下载地址为:https://www.microsoft.com/en-us/download/confirmation.aspx?id=23654

准备二:若本机没有安装LINQ to SQL工具,可参考安装教程:https://blog.csdn.net/u011176794/article/details/90287293

准备三:添加新建项,选择LINQ to SQL类,命名为Sample。

准备四:服务器资源管理器的数据连接中,右键添加连接,依导向连接至SQL Server数据库。

准备五:将相关数据表拖至Sample.dbml中并保存。

准备六:添加引用System.Data.Linq。

下面代码演示LINQ to SQL:

C# LINQ学习笔记一:走进LINQ的世界第2张C# LINQ学习笔记一:走进LINQ的世界第12张
    classProgram
    {
        static void Main(string[] args)
        {
            #region LINQ to SQL
            var db = newSampleDataContext();
            var query =
                from cust indb.Customers
                where cust.City == "London"
                selectcust;
            foreach (var item inquery)
            {
                Console.WriteLine($"CustomerID={item.CustomerID}");
            }
            Console.Read();
            #endregion}
    }
View Code

运行结果如下:

C# LINQ学习笔记一:走进LINQ的世界第13张

1.3查询

查询指定要从数据源中检索的信息,可以指定在返回这些信息之前如何对其进行排序、分组和结构化。 查询存储在查询变量中,并用查询表达式进行初始

化。之前的示例中的查询是从整数数组中返回所有的偶数。该查询表达式包含三个子句:fromwhereselect。如果您熟悉SQL,您会注意到这些子句的

顺序与SQL中的顺序相反,from子句指定数据源,where子句指定应用筛选器,select子句指定返回的元素的类型。目前需要注意的是,在LINQ中,查询

变量本身不执行任何操作并且不返回任何数据,它只是存储在以后某个时刻执行查询时为生成结果而必需的信息。

1.4 查询执行

1.延迟执行

如前所述,查询变量本身只是存储查询命令,实际的查询执行会延迟到在foreach语句中循环访问查询变量时发生,此概念称为“延迟执行”。

2.强制立即执行

对一系列源元素执行聚合函数的查询必须首先循环访问这些元素,CountMaxAverageFirst就属于此类查询。由于查询本身必须使用foreach以便

返回结果,因此这些查询在执行时不使用显式foreach语句。另外还要注意,这些类型的查询返回单个值,而不是IEnumerable集合。

C# LINQ学习笔记一:走进LINQ的世界第2张C# LINQ学习笔记一:走进LINQ的世界第15张
    classProgram
    {
        static void Main(string[] args)
        {
            #region LINQ查询强制立即执行一
            var nums = new int[7] { 0, 1, 2, 3, 4, 5, 6};
            var query =
                from num innums
                where (num % 2) == 0
                selectnum;
            var numCount =query.Count();
            Console.WriteLine($"NumCount={numCount}");
            Console.Read();
            #endregion}
    }
View Code
运行结果如下:
C# LINQ学习笔记一:走进LINQ的世界第16张

若要强制立即执行任意查询并缓存其结果,可以调用ToList<TSource>ToArray<TSource>方法。

C# LINQ学习笔记一:走进LINQ的世界第2张C# LINQ学习笔记一:走进LINQ的世界第18张
    classProgram
    {
        static void Main(string[] args)
        {
            #region LINQ查询强制立即执行二
            var nums = new int[7] { 0, 1, 2, 3, 4, 5, 6};

            var query2 =(from num innums
                where (num % 2) == 0
                selectnum).ToList();

            var query3 =(from num innums
                 where (num % 2) == 0
                 selectnum).ToArray();

            Console.WriteLine($"NumCount={query2.Count}");
            Console.WriteLine($"NumCount={query3.Length}");
            Console.Read();
            #endregion}
    }
View Code

运行结果如下:

C# LINQ学习笔记一:走进LINQ的世界第19张

二、基本 LINQ 查询操作

2.1 获取数据源:from

在LINQ查询中,第一步是指定数据源。像在大多数编程语言中一样,必须先声明变量,才能使用它。在LINQ查询中,最先使用from子句的目的是引入数据

源和范围变量。

C# LINQ学习笔记一:走进LINQ的世界第2张C# LINQ学习笔记一:走进LINQ的世界第21张
    classProgram
    {
        static void Main(string[] args)
        {
            #region LINQ to SQL
            var db = newSampleDataContext();

            //query是IEnumerable<Cutsomer>类型
            //数据源(db.customers)和范围变量(cust)
            var query =
                from cust indb.Customers
                where cust.City == "London"
                selectcust;

            foreach (var item inquery)
            {
                Console.WriteLine($"CustomerID={item.CustomerID}");
            }
            Console.Read();
            #endregion}
    }
View Code

范围变量类似于foreach循环中的迭代变量,但在查询表达式中,实际上不发生迭代。执行查询时,范围变量将用作对customers中的每个后续元素的引用。

因为编译器可以推断cust的类型,所以您不必显式指定此类型。

2.2 筛选:where

也许最常用的查询操作是应用布尔表达式形式的筛选器,此筛选器使查询只返回那些表达式结果为true的元素。使用where子句生成结果,实际上,筛选器

指定从源序列中排除哪些元素。

您可以使用熟悉的C#逻辑AND(&&)OR(||)运算符来根据需要在where子句中应用任意数量的筛选表达式。

C# LINQ学习笔记一:走进LINQ的世界第2张C# LINQ学习笔记一:走进LINQ的世界第23张
    classProgram
    {
        static void Main(string[] args)
        {
            #region LINQ 筛选:where
            var db = newSampleDataContext();

            var query1 =
                from cust indb.Customers
                where cust.City == "London" && cust.CustomerID == "AROUT"
                selectcust;
            var query2 =
                from cust indb.Customers
                where cust.City == "London" || cust.City == "Paris"
                selectcust;

            foreach (var item inquery1)
            {
                Console.WriteLine($"query1->City={item.City},CustomerID={item.CustomerID}");
            }
            foreach (var item inquery2)
            {
                Console.WriteLine($"query2->City={item.City},CustomerID={item.CustomerID}");
            }
            Console.Read();
            #endregion}
    }
View Code

运行结果如下:

C# LINQ学习笔记一:走进LINQ的世界第24张

2.3 排序:orderby

通常可以很方便地将返回的数据进行排序。orderby子句将使返回的序列中的元素按照被排序的类型的默认比较器进行排序。

C# LINQ学习笔记一:走进LINQ的世界第2张C# LINQ学习笔记一:走进LINQ的世界第26张
    classProgram
    {
        static void Main(string[] args)
        {
            #region LINQ 排序:orderby
            var db = newSampleDataContext();
            var query =
                from cust indb.Customers
                where cust.City == "London"
                orderbycust.CustomerID
                selectcust;
            foreach (var item inquery)
            {
                Console.WriteLine($"CustomerID={item.CustomerID}");
            }
            Console.Read();
            #endregion}
    }
View Code

运行结果如下:

C# LINQ学习笔记一:走进LINQ的世界第27张

2.4 分组:group

使用group子句,您可以按指定的键分组结果。

C# LINQ学习笔记一:走进LINQ的世界第2张C# LINQ学习笔记一:走进LINQ的世界第29张
    classProgram
    {
        static void Main(string[] args)
        {
            #region LINQ 分组一:group
            var db = newSampleDataContext();
            var query =
                from cust indb.Customers
                where cust.City == "London" || cust.City == "Paris"group cust by cust.City;
            foreach (var group inquery)
            {
                Console.WriteLine(group.Key);
                foreach (var cust ingroup)
                {
                    Console.WriteLine($"City={cust.City},CustomerID={cust.CustomerID}");
                }
            }
            Console.Read();
            #endregion}
    }
View Code

运行结果如下:

C# LINQ学习笔记一:走进LINQ的世界第30张

在本例中,cust.City是键。

在使用group子句结束查询时,结果采用列表的列表形式。列表中的每个元素是一个具有Key成员及根据该键分组的元素列表的对象。在循环访问生成组

序列的查询时,您必须使用嵌套的foreach循环。外部循环用于循环访问每个组,内部循环用于循环访问每个组的成员。

如果您必须引用组操作的结果,可以使用into关键字来创建可进一步查询的标识符。

C# LINQ学习笔记一:走进LINQ的世界第2张C# LINQ学习笔记一:走进LINQ的世界第32张
    classProgram
    {
        static void Main(string[] args)
        {
            #region LINQ 分组二:group
            var db = newSampleDataContext();
            var query =
                from cust indb.Customers
                where cust.City == "London" || cust.City == "Paris"group cust by cust.City into custGroup
                where custGroup.Count() > 2
                orderbycustGroup.Key
                selectcustGroup;
            foreach (var group inquery)
            {
                Console.WriteLine(group.Key);
                foreach (var cust ingroup)
                {
                    Console.WriteLine($"City={cust.City},CustomerID={cust.CustomerID}");
                }
            }
            Console.Read();
            #endregion}
    }
View Code

运行结果如下:

C# LINQ学习笔记一:走进LINQ的世界第33张

2.5 联接:join

联接运算创建数据源中没有显式建模的序列之间的关联。例如,您可以执行联接来查找位于同一地点的所有客户和经销商。在LINQ中,join子句始终针对

对象集合而非直接针对数据库表运行。

C# LINQ学习笔记一:走进LINQ的世界第2张C# LINQ学习笔记一:走进LINQ的世界第35张
    classProgram
    {
        static void Main(string[] args)
        {
            #region LINQ 联接:join
            var db = newSampleDataContext();
            var qurey =
                from order indb.Orders
                join cust indb.Customers on order.CustomerID equals cust.CustomerID
                select new{ order.OrderID, order.CustomerID, cust.ContactName };
            foreach (var item in qurey.Take(5))
            {
                Console.WriteLine($"OrderID={item.OrderID},CustomerID={item.CustomerID},ContactName={item.ContactName}");
            }
            Console.Read();
            #endregion}
    }
View Code

运行结果如下:

C# LINQ学习笔记一:走进LINQ的世界第36张

2.6 选择(投影):select

select子句生成查询结果并指定每个返回的元素的“形状”或类型。

例如,您可以指定结果包含的是整个Customer对象、仅一个成员、成员的子集或者某个基于计算或新对象创建的完全不同的结果类型。当select子句生成除源

元素副本以外的内容时,该操作称为“投影”。

三、使用 LINQ 进行数据转换

语言集成查询 (LINQ) 不但是检索数据的利器,而且还是一个功能强大的数据转换工具。通过使用LINQ查询,您可以将源序列用作输入,并采用多种方式修改

它以创建新的输出序列。您可以通过排序及分组来修改该序列,而不必修改元素本身。但是,LINQ 查询的最强大的功能是能够创建新类型。这一功能在select子

句中实现。

3.1 将多个输入联接到一个输出序列

C# LINQ学习笔记一:走进LINQ的世界第2张C# LINQ学习笔记一:走进LINQ的世界第38张
    /// <summary>
    ///学生类
    /// </summary>
    classStudent
    {
        public string Name { get; set; }

        public int Age { get; set; }

        public string City { get; set; }

        public List<int> Scores { get; set; }
    }

    /// <summary>
    ///教师类
    /// </summary>
    classTeacher
    {
        public string Name { get; set; }

        public int Age { get; set; }

        public string City { get; set; }
    }      
    
    classProgram
    {
        static void Main(string[] args)
        {
            #region LINQ 将多个输入联接到一个输出序列
            //创建第一个数据源
            var students = new List<Student>()
            {
                newStudent()
                {
                    Age = 19,
                    City = "广州",
                    Name = "小A",
                    Scores = new List<int>(){85,88,83,97}
                },
                newStudent()
                {
                    Age = 19,
                    City = "深圳",
                    Name = "小B",
                    Scores = new List<int>(){86,80,85,92}
                }
            };

            //创建第二个数据源
            var teachers = new List<Teacher>()
            {
                newTeacher()
                {
                    Age = 30,
                    City = "广州",
                    Name = "张A"},
                newTeacher()
                {
                    Age = 31,
                    City = "广州",
                    Name = "李A"}
            };

            //创建查询
            var query =(
                    from student instudents
                    where student.City == "广州"
                    selectstudent.Name
                ).Concat
                (
                    from teacher inteachers
                    where teacher.City == "广州"
                    selectteacher.Name
                );

            //执行查询
            foreach (var person inquery)
            {
                Console.WriteLine(person);
            }

            Console.Read();
            #endregion}
    }
View Code

运行结果如下:

C# LINQ学习笔记一:走进LINQ的世界第39张

3.2 选择各个源元素的子集

1. 若要只选择源元素的一个成员,请使用点运算。

var query = 
    from cust indb.Customers
    select cust.City;

2.若要创建包含源元素的多个属性的元素,可以使用具有命名对象或匿名类型的对象初始值设定项。

var query = 
    from cust indb.Customer
    select new { cust.Name, cust.City };

3.3 将内存中的对象转换为XML

C# LINQ学习笔记一:走进LINQ的世界第2张C# LINQ学习笔记一:走进LINQ的世界第41张
    /// <summary>
    ///学生类
    /// </summary>
    classStudent
    {
        public string Name { get; set; }

        public int Age { get; set; }

        public string City { get; set; }

        public List<int> Scores { get; set; }
    }     
    
    classProgram
    {
        static void Main(string[] args)
        {
            #region LINQ 将内存中的对象转换为XML
            //创建数据源
            var students = new List<Student>()
            {
                newStudent()
                {
                    Age = 19,
                    City = "广州",
                    Name = "小A",
                    Scores = new List<int>(){85,88,83,97}
                },
                newStudent()
                {
                    Age = 19,
                    City = "深圳",
                    Name = "小B",
                    Scores = new List<int>(){86,80,85,92}
                }
            };
            //创建查询
            var studentsToXml = newXElement
                (
                    "Root",
                    from student instudents
                    let x = $"{student.Scores[0]},{student.Scores[1]},{student.Scores[2]},{student.Scores[3]}"
                    select newXElement
                        (
                            "student",
                            new XElement("Name", student.Name),
                            new XElement("Age", student.Age),
                            new XElement("Scores", x)
                        )
                );

            //执行查询
Console.WriteLine(studentsToXml);
            Console.Read();
            #endregion}
    }
View Code

运行结果如下:

C# LINQ学习笔记一:走进LINQ的世界第42张

3.4 对源元素执行操作

输出序列可能不包含源序列的任何元素或元素属性,它可能是通过将源元素用作输入参数计算出的值的序列。

C# LINQ学习笔记一:走进LINQ的世界第2张C# LINQ学习笔记一:走进LINQ的世界第44张
    classProgram
    {
        static void Main(string[] args)
        {
            #region LINQ 对源元素执行操作
            //数据源
            double[] radius = { 1, 2, 3};
            //创建查询
            var query =
                from radiu inradius
                select $"{3.14 * radiu * radiu}";
            //执行查询
            foreach (var item inquery)
            {
                Console.WriteLine(item);
            }
            Console.Read();
            #endregion}
    }
View Code

运行结果如下:

C# LINQ学习笔记一:走进LINQ的世界第45张

四、LINQ 查询操作的类型关系

LINQ 查询操作在数据源、查询本身及查询执行中是强类型的。查询中变量的类型必须与数据源中元素的类型和foreach语句中迭代变量的类型兼容。强类型可

以保证在编译时捕获类型错误,以便及时改正。

4.1 不转换源数据的查询

下图演示不对数据执行转换的LINQ to OBJECT查询操作。源包含一个字符串序列,查询输出也是一个字符串序列。

C# LINQ学习笔记一:走进LINQ的世界第46张

①数据源的类型参数决定范围变量的类型。

select语句返回Name属性,而非完整的Customer对象。因为Name是一个字符串,所以custNameQuery的类型参数是string,而非Customer。

③因为custNameQuery是一个字符串序列,所以foreach循环的迭代变量也必须是string

4.2 转换源数据的查询

下图演示对数据执行简单转换的LINQ to SQL查询操作。查询将一个Customer对象序列用作输入,并只选择结果中的Name属性。因为Name是一个字符串,

所以查询生成一个字符串序列作为输出。

C# LINQ学习笔记一:走进LINQ的世界第47张

①数据源的类型参数决定范围变量的类型。

select语句返回Name属性,而非完整的Customer对象。因为Name是一个字符串,所以custNameQuery的类型参数是string,而非Customer。

③因为custNameQuery是一个字符串序列,所以foreach循环的迭代变量也必须是string

下图演示另一种转换。select语句返回只捕获原始Customer对象的两个成员的匿名类型。

C# LINQ学习笔记一:走进LINQ的世界第48张

①数据源的类型参数始终为查询中的范围变量的类型。

②因为select语句生成匿名类型,所以必须使用var隐式类型化查询变量。

③因为查询变量的类型是隐式的,所以foreach循环中的迭代变量也必须是隐式的。

4.3让编译器推断类型信息

您也可以使用关键字var可用于查询操作中的任何局部变量。但是,编译器为查询操作中的各个变量提供强类型。

C# LINQ学习笔记一:走进LINQ的世界第49张

五、LINQ 中的查询语法和方法语法

我们编写的LINQ查询语法,在编译代码时,CLR会将查询语法转换为方法语法。这些方法调用标准查询运算符的名称类似Where、Select、GroupBy、Join、

Max和Average,我们也是可以直接使用这些方法语法的。

查询语法和方法语法语义相同,但是,许多人员发现查询语法更简单、更易于阅读。某些查询必须表示为方法调用。例如,必须使用方法调用表示检索元素

的数量与指定的条件的查询,还必须使用方法需要检索元素的最大值在源序列的查询。System.Linq命名空间中的标准查询运算符的参考文档通常使用方法语法。

5.1 标准查询运算符扩展方法

C# LINQ学习笔记一:走进LINQ的世界第2张C# LINQ学习笔记一:走进LINQ的世界第51张
    classProgram
    {
        static void Main(string[] args)
        {
            #region LINQ 标准查询运算符扩展方法
            var nums = new int[4] { 1, 2, 3, 4};

            //创建查询表达式
            var query1 = 
                from num innums
                where num % 2 == 0
                orderbynum descending
                selectnum;

            Console.WriteLine("Query1's result:");
            foreach (var num inquery1)
            {
                Console.WriteLine(num);
            }

            //使用方法进行查询
            var query2 = nums.Where(num => num % 2 == 0).OrderByDescending(num =>num);

            Console.WriteLine("Query2's result:");
            foreach (var num inquery2)
            {
                Console.WriteLine(num);
            }

            Console.Read();
            #endregion}
    }
View Code

运行结果如下:

C# LINQ学习笔记一:走进LINQ的世界第52张

两个示例的输出是相同的。您可以看到两种形式的查询变量的类型是相同的:IEnumerable<T>

若要了解基于方法的查询,让我们进一步地分析它。注意,在表达式的右侧,where子句现在表示为对numbers对象的实例方法,在您重新调用该对象时其类型

为IEnumerable<int>。如果您熟悉泛型IEnumerable<T>接口,那么您就会了解,它不具有Where方法。但是,如果您在Visual Studio IDE中调用IntelliSense完成

列表,那么您不仅将看到Where方法,而且还会看到许多其他方法,如SelectSelectManyJoinOrderby

下面是所有标准查询运算符:

C# LINQ学习笔记一:走进LINQ的世界第53张

尽管看起来IEnumerable<T>似乎已被重新定义以包括这些附加方法,但事实上并非如此,这些标准查询运算符都是作为“扩展方法”实现的。

5.2 Lambda 表达式

在前面的示例中,通知该条件表达式 (num % 2 == 0) 是作为内联参数。Where方法:Where (num => num % 2 == 0) 此内联表达式称为lambda表达式。将代码

编写为匿名方法或泛型委托或表达式树是一种便捷的方法,否则编写起来就要麻烦得多。=>是lambda运算符,可读为“goes to”。运算符左侧的num是输入变量,

与查询表达式中的num相对应。编译器可推断num的类型,因为它了解numbers是泛型IEnumerable<T>类型。Lambda表达式与查询语法中的表达式或任何其他C#

表达式或语句中的表达式相同,它可以包括方法调用和其他复杂逻辑,“返回值”就是表达式结果。

5.3 查询的组合性

在上面的代码示例中,请注意OrderBy方法是通过在对Where的调用中使用点运算符来调用的。Where生成筛选序列,然后Orderby通过对该序列排序来对它进行

操作。因为查询会返回IEnumerable,所以您可通过将方法调用链接在一起,在方法语法中将这些查询组合起来。这就是在您通过使用查询语法编写查询时编译器在

后台所执行的操作,并且由于查询变量不存储查询的结果,因此您可以随时修改它或将它用作新查询的基础,即使在执行它后。

免责声明:文章转载自《C# LINQ学习笔记一:走进LINQ的世界》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇java字符串与基础混淆表单绑定 v-model的使用下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Delphi7中 string, AnsiString, Utf8String,WideString的区别分析(转)

Windows系统上的 Notepad.exe 打开文件后,点击“文件”菜单中的“另存为”命令,会跳出一个对话框,在最底部有一个“编码”的下拉条。里面有四个选项:ANSI,Unicode,Unicode big endian 和 UTF-8。1)ANSI是默认的编码方式。对于英文文件是ASCII编码,对于简体中文文件是GB2312编码(只针对Windows...

关于c++正则表达式的用法

本人最近在做一个项目,这个项目里面有一个功能是这样的,要求这个项目中提供搜索功能,简单的说,如果里面输入1-10 11,15,27,39这个字符串,那么你就要从中找到1,2,3,4,5,6,7,8,9,10和11,15,27,39等等这些数字。我考虑了很久,决定使用正则表达式来做,采用的原因有两点:其一,因为考虑到范围的问题(比如说位数不能超过三位)这样的...

跟我一起玩Win32开发(10):绘图(C)

今天我们来欣赏一下用于填充图形的函数,当然我不会逐个去介绍,因为我们参考MSDN直接套参数就可以了。 SetDCBrushColor函数有必要扯一下,它的声明如下: [cpp] view plain copy  COLORREF SetDCBrushColor(     __in  HDC hdc,     __in  COLORREF crCo...

ReactNative: 了解相机第三方库react-native-camera的使用

一、简介 在前一篇文章中,初步介绍了RN提供的关于相机功能CameraRoll的使用了。很多时候,这种最基础的API有时很难满足功能需求,此时,如果不想重复造轮子,我们可以选择一个完善好用的第三库。react-native-camera就是一个非常不错的关于相机功能的第三方库,使用这个框架基本能满足大多数的需求,现在来简单研究一下。 二、安装 1、同样地道...

使用Lucene.NET实现数据检索功能

引言     在软件系统中查询数据是再平常不过的事情了,那当数据量非常大,数据存储的媒介不是数据库,或者检索方式要求更为灵活的时候,我们该如何实现数据的检索呢?为数据建立索引吧,利用索引技术可以更灵活更快捷的实现检索功能。     以下我要介绍的是.NET版的Lucene在实际项目中是如何应用的。 案例概要     我以一个文件检索系统为例,主要功能就...

fastJSON 使用总结

1.介绍Fastjson Fastjson是一个Java语言编写的JSON处理器。 如果获得Fastjson?https://github.com/alibaba/fastjson 2.使用Fastjson Json互转List<T> 比如说List<Strudent> List转Json List<Student>...