Linq是语言集成查询的简称。Linq简化了语言查询,是的程序员可以使用相同的语法查询不同的数据源。

        本文是闲暇之余学习Linq的产物。代码是花了大约一周的业余时间组织的,敲出来只是为了记住它。本文使用的Linq查询包含了两种方式,一种是直接查询,另一种是使用System.Linq中定义的扩展方法进行的查询。对于扩展方法查询的方式,使用了大量的Lambda表的是和系统定义的委托Func<T>。不熟悉这两个东西的童鞋们可以在本博找到相关的文章:

Lambda表达式学习记录】【Action<T>和Func<T>委托

一、准备供查询的数据 

本文首先构建一个提供数据的实体类供以后的查询使用。本文使用的实体类包含了1950到2008年一级方程式锦标赛的冠军车队和冠军赛手。这些数据是使用了实体类和列表来准备的。

首先定义代表赛手的实体类Racer。Racer类定义了几个属性和一个重载的ToString()方法,该方法以指定的格式显示赛手。Racer类实现了IFormattable接口,以支持格式字符串的不同变体。这个类还实现类IComparable<T>接口,用以根据赛手的LastName进行排序。为了执行高级查询Racer类同时包含了单值属性如FirstName、LastName、Wins(获胜次数)、Country(国籍)和Starts。同时也包含了多值属性如:Cars(赛手在获得冠军的年份所使用的赛车)和Years(赛手获得冠军的年份,赛手可以多次获得冠军)。这个类具体的实现如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyLinqTest
{
    [Serializable]
    public class Racer : IComparable<Racer>, IFormattable
    {
        public Racer(string firstName = null,
            string lastName = null,
            string country = null,
            int starts = 0,
            int wins = 0,
            IEnumerable<int> years = null,
            IEnumerable<string> cars = null)
        {
            this.FirstName = firstName;
            this.LastName = lastName;
            this.Country = country;
            this.Starts = starts;
            this.Wins = wins;
            var yearsList = new List<int>();
            foreach (var year in years)
            {
                yearsList.Add(year);
            };
            this.Years = yearsList.ToArray();

            var carList = new List<string>();
            foreach (var car in cars)
            {
                carList.Add(car);
            }
            this.Cars = carList.ToArray();
        }

        public string FirstName { get; set; }
        public string LastName { get; set; }
        public int Wins { get; set; }
        public string Country { get; set; }
        public int Starts { get; set; }
        public string[] Cars { get; private set; }
        public int[] Years { get; private set; }

        public override string ToString()
        {
            return String.Format("{0} {1}", FirstName, LastName);
        }

        public string ToString(string format)
        {
            return ToString(format, null);
        }

        public string ToString(string format, IFormatProvider formatProvider)
        {
            switch (format)
            {
                case null:
                case "N":
                    return ToString();
                case "F":
                    return FirstName;
                case "L":
                    return LastName;
                case "C":
                    return Country;
                case "S":
                    return Starts.ToString();
                case "W":
                    return Wins.ToString();
                case "A":
                    return String.Format("{0} {1}, {2}; starts: {3}, wins: {4}",
                          FirstName, LastName, Country, Starts, Wins);
                default:
                    throw new FormatException(String.Format("Format {0} not supported", format));
            }
        }

        public int CompareTo(Racer other)
        {
            if (other == null)
            {
                throw new ArgumentNullException("Other");
            }
            return this.LastName.CompareTo(other.LastName);
        }
    }
}

 

第二个实体类是Team。这个类包含了车队冠军的名字和获得冠军的年份。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyLinqTest
{
    [Serializable]
    public class Team
    {
        public Team(string name,params int[] years)
        {
            this.Name = name;
            this.Years = years;
        }
        public string Name { get; private set; }
        public int[] Years { get; private set; }
    }
}

 

第三个类是Formula1.这个类定义方法GetChampions方法返回一组表示以及方程式赛车冠军的列表。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyLinqTest
{
    public static class Formula1
    {
        private static List<Racer> racers;

        public static IList<Racer> GetChampions()
        {
            if (racers == null)
            {
                racers = new List<Racer>();
                racers.Add(new Racer("Nino", "Farina", "Italy", 33, 5, new int[] { 1950 }, new string[] { "Alfa Romeo" }));
                racers.Add(new Racer("Alberto", "Ascari", "Italy", 32, 10, new int[] { 1952, 1953 }, new string[] { "Ferrari" }));
                racers.Add(new Racer("Juan Manuel", "Fangio", "Argentina", 51, 24, new int[] { 1951, 1954, 1955, 1956, 1957 }, new string[] { "Alfa Romeo", "Maserati", "Mercedes", "Ferrari" }));
                racers.Add(new Racer("Mike", "Hawthorn", "UK", 45, 3, new int[] { 1958 }, new string[] { "Ferrari" }));
                racers.Add(new Racer("Phil", "Hill", "USA", 48, 3, new int[] { 1961 }, new string[] { "Ferrari" }));
                racers.Add(new Racer("John", "Surtees", "UK", 111, 6, new int[] { 1964 }, new string[] { "Ferrari" }));
                racers.Add(new Racer("Jim", "Clark", "UK", 72, 25, new int[] { 1963, 1965 }, new string[] { "Lotus" }));
                racers.Add(new Racer("Jack", "Brabham", "Australia", 125, 14, new int[] { 1959, 1960, 1966 }, new string[] { "Cooper", "Brabham" }));
                racers.Add(new Racer("Denny", "Hulme", "New Zealand", 112, 8, new int[] { 1967 }, new string[] { "Brabham" }));
                racers.Add(new Racer("Graham", "Hill", "UK", 176, 14, new int[] { 1962, 1968 }, new string[] { "BRM", "Lotus" }));
                racers.Add(new Racer("Jochen", "Rindt", "Austria", 60, 6, new int[] { 1970 }, new string[] { "Lotus" }));
                racers.Add(new Racer("Jackie", "Stewart", "UK", 99, 27, new int[] { 1969, 1971, 1973 }, new string[] { "Matra", "Tyrrell" }));
                racers.Add(new Racer("Emerson", "Fittipaldi", "Brazil", 143, 14, new int[] { 1972, 1974 }, new string[] { "Lotus", "McLaren" }));
                racers.Add(new Racer("James", "Hunt", "UK", 91, 10, new int[] { 1976 }, new string[] { "McLaren" }));
                racers.Add(new Racer("Mario", "Andretti", "USA", 128, 12, new int[] { 1978 }, new string[] { "Lotus" }));
                racers.Add(new Racer("Jody", "Scheckter", "South Africa", 112, 10, new int[] { 1979 }, new string[] { "Ferrari" }));
                racers.Add(new Racer("Alan", "Jones", "Australia", 115, 12, new int[] { 1980 }, new string[] { "Williams" }));
                racers.Add(new Racer("Keke", "Rosberg", "Finland", 114, 5, new int[] { 1982 }, new string[] { "Williams" }));
                racers.Add(new Racer("Niki", "Lauda", "Austria", 173, 25, new int[] { 1975, 1977, 1984 }, new string[] { "Ferrari", "McLaren" }));
                racers.Add(new Racer("Nelson", "Piquet", "Brazil", 204, 23, new int[] { 1981, 1983, 1987 }, new string[] { "Brabham", "Williams" }));
                racers.Add(new Racer("Ayrton", "Senna", "Brazil", 161, 41, new int[] { 1988, 1990, 1991 }, new string[] { "McLaren" }));
                racers.Add(new Racer("Nigel", "Mansell", "UK", 187, 31, new int[] { 1992 }, new string[] { "Williams" }));
                racers.Add(new Racer("Alain", "Prost", "France", 197, 51, new int[] { 1985, 1986, 1989, 1993 }, new string[] { "McLaren", "Williams" }));
                racers.Add(new Racer("Damon", "Hill", "UK", 114, 22, new int[] { 1996 }, new string[] { "Williams" }));
                racers.Add(new Racer("Jacques", "Villeneuve", "Canada", 165, 11, new int[] { 1997 }, new string[] { "Williams" }));
                racers.Add(new Racer("Mika", "Hakkinen", "Finland", 160, 20, new int[] { 1998, 1999 }, new string[] { "McLaren" }));
                racers.Add(new Racer("Michael", "Schumacher", "Germany", 250, 91, new int[] { 1994, 1995, 2000, 2001, 2002, 2003, 2004 }, new string[] { "Benetton", "Ferrari" }));
                racers.Add(new Racer("Fernando", "Alonso", "Spain", 132, 21, new int[] { 2005, 2006 }, new string[] { "Renault" }));
                racers.Add(new Racer("Kimi", "Räikkönen", "Finland", 148, 17, new int[] { 2007 }, new string[] { "Ferrari" }));
                racers.Add(new Racer("Lewis", "Hamilton", "UK", 44, 9, new int[] { 2008 }, new string[] { "McLaren" }));
            }
            return racers;
        }

        private static List<Team> teams;
        public static IList<Team> GetConstructorChampions()
        {
            if (teams == null)
            {
                teams = new List<Team>()
                {
                    new Team("Vanwall", 1958),
                    new Team("Cooper", 1959, 1960),
                    new Team("Ferrari", 1961, 1964, 1975, 1976, 1977, 1979, 1982, 1983, 1999, 2000, 2001, 2002, 2003, 2004, 2007, 2008),
                    new Team("BRM", 1962),
                    new Team("Lotus", 1963, 1965, 1968, 1970, 1972, 1973, 1978),
                    new Team("Brabham", 1966, 1967),
                    new Team("Matra", 1969),
                    new Team("Tyrrell", 1971),
                    new Team("McLaren", 1974, 1984, 1985, 1988, 1989, 1990, 1991, 1998),
                    new Team("Williams", 1980, 1981, 1986, 1987, 1992, 1993, 1994, 1996, 1997),
                    new Team("Benetton", 1995),
                    new Team("Renault", 2005, 2006 )
                };
            }
            return teams;
        }
    }
}

 

这个类还定义了一个方法:GetConstructorChampions()。用于返回所有车队冠军的列表。

        二、System.Linq中的扩展方法 

       扩展方法的作用是将方法写入最初没有定义该方法的类中。还可以将方法添加到实现某个特定接口的任何类中,这样多个类就可以使用相同的实现代码。对于扩展方法本文不做详细介绍,只是扩展方法在Linq查询中使用较多需要预先了解。尤其是System.Core程序集下定义的System.Linq方法。本文后边将会用到。

        三、使用Linq进行查询 

有了这些预备知识和实体类,我们就可以使用Linq进行查询了。

       1、简单的筛选

使用Where子句可以对数据源进行简单的筛选。下变例子是找出至少赢得15场比赛的奥地利车手:

        /// <summary>
/// 1、最简单的查询
/// </summary>
static void LinqQuery1()
{
var query = from r in Formula1.GetChampions()
where (r.Country == "Brazil" || r.Country == "Austria") && r.Wins > 15
orderby r.Wins descending
select r;
foreach (var racer in query)
{
Console.WriteLine("{0:A}", racer);
}
}

 

这段代码的功能可以使用System.Linq中的扩展方法来实现:

【代码】

            var query2 = Formula1.GetChampions()
.Where(r => r.Country == "Brazil" || r.Country == "Austria")
.Select(r=>r);

 

注:并不是所有的查询都可以使用Linq查询或者扩展方法都可以实现的。高级查询需要使用扩展方法。

       2、用索引进行筛选

Where()扩展方法的一个重载中,可以对该方法传递第二个参数:索引。索引是筛选器返回的每个结果的计数器,可以在表达式中使用索引,执行一些索引相关的计算。现编的代码使用Where()扩展方法,返回姓氏以A开头,索引为偶数的车手:

        /// <summary>
/// 2、使用索引i进行筛选
         /// </summary>
static void LinqQuery2()
{

//使用索引i进行筛选
             var query = Formula1.GetChampions()
.Where((r, i) => r.LastName.StartsWith("A") && i % 2 != 0);
foreach (var item in query)
{
Console.WriteLine("{0:A}", item);
}
}

       3、筛选出不同的数据类型

使用OfType()扩展方法,可以实现基于类型的筛选。下面的代码中定义了包含了string和int类型的对象,使用OfType()方法从集合中找出字符串:

        /// <summary>
/// 3、类型筛选
         /// </summary>
static void LinqQuery3()
{
object[] data = { "one", 1, 2, 3, "two", "three" };
var query = data.OfType<string>();

foreach (var item in query)
{
Console.WriteLine(item);
}
}

 

       4、复合的from子句

复合的from子句用于对这样一种情况的查询:需要根据对象的一个成员进行筛选,而这个成员本身是一组数据。

本例中,Racer类定义的属性Cars就是这样的一个属性。Cars是一个字符串数组。

使用如下的Linq查询可以筛选出嘉实法拉利的所有冠军:

            var query = from r in Formula1.GetChampions()
from c in r.Cars
where c == "Ferrari"
orderby r.LastName
select r;

 

其中,第一个from子句用于访问从Formyla1.GetChampions方法返回的Racer对象,第二个from子句访问Racer类的Cars属性,返回所有string类型的赛车,最后使用Where子句从这些赛车中筛选出所有冠军。

这里C#编译器将符合的from子句和Linq查询转换成SelectMany()方法,SelectMany()方法可以用于迭代序列的序列。使用SelectMany()扩展方法的代码如下:

            var query = Formula1.GetChampions()
.SelectMany(r => r.Cars, (r, c) => new { Racer = r, Car = c })
.Where(r => r.Car == "Ferrari")
.OrderBy(r => r.Racer.FirstName)
.Select(r => r.Racer.FirstName + " " + r.Racer.LastName);

 

这里SelectMany()方法的第一个参数是隐式参数,他从GetChampions方法中接收Racer对象序列,第二个参数是collectionSelector委托,其中定义了内部序列。在Lambda表达式r=>r.Cars中,返回赛车集合。第三个参数是一个Func<T>委托,这里为每个Car调用该委托接收Racer和Cars对象。Lambda表达式创建了一个包含了Racer和Cars属性的匿名的类型。这个SelectMany方法的结果摊平了赛手和赛车的层次结构,为每个赛车返回匿名类型的一个新对象耦合。

这段解释有点拗口,因为Lambda表达式确实比较难以解释,还有使用了几个Func<T>委托,不了解委托看这段代码简直就是天书。不过VS的职能提示挺管用的,在敲出几个代码之后看看他的提示在继续写也是不错的。

       5、对筛选结果进行排序

使用orderby和orderby descending子句或者OrderBy()和OrderByDescending()扩展方法可以实现对筛选结果的排序。

下面这段代码是对筛选出来的赛手使用赢得比赛的次数进行排序:

            //简单的Linq语句查询排序
var query1 = from r in Formula1.GetChampions()
where r.Country == "Brazil"
orderby r.Wins descending
select r;

 

转换成扩展方法后的实现:

            //使用扩展方法
var query2 = Formula1.GetChampions()
.Where(r => r.Country == "Brazil")
.OrderByDescending(r => r.Wins)
.ThenByDescending(r=>r.LastName)
.Select(r => r);

最后还可以使用Take方法对结果进一步筛选:

            //使用Take子句提取前十项数据
var query3 = (from r in Formula1.GetChampions()
orderby r.Country, r.LastName, r.FirstName
select r)
.Take(10);

//使用扩展方法查询
var query = Formula1.GetChampions()
.OrderBy(r => r.Country)
.ThenBy(r => r.LastName)
.ThenBy(r => r.FirstName)
.Take(10)
.Select(r => r);

       6、对筛选结果进行分组

使用group子句和GroupBy()扩展方法可以对查询结果进行分组。下边的例子是将赛车冠军按照国家进行分组,并列出一个国家赛车冠军的总数:

            //简ò单蹋inq分?组哩?
var query = from r in Formula1.GetChampions()
group r by r.Country into g
orderby g.Count() descending, g.Key
where g.Count() >= 2
select new
{
Country = g.Key,
Count = g.Count()
};

 

子句group r by r.Country into g 根据Country属性组合所有赛车手到一个新的标识符g中。g用于以后访问分组的结果信息。group子句的结果根据扩展方法Count()的结果进行排序。Select子句创建了一个带Country和Count属性的匿名类型。这里有一个对象需要注意:g.Key。这指的是是group方法筛选的依据,本例中g.Key就是分组依据Country。

直接使用扩展方法中的GroupBy()和ThenBy()方法也可以实现相应的筛选功能:

            var query = Formula1.GetChampions()
.GroupBy(r => r.Country)
.OrderByDescending(g => g.Count())
.ThenBy(g => g.Key)
.Where(g => g.Count() >= 2)
.Select(g => new { Country = g.Key, Count = g.Count() });

 

这里可以看出子句group r by r.Country into g被解析为GroupBy(r=>r.Country),返回分组序列,之后进行了排序和筛选等见大的操作即得到了需要的结果。

       7、对嵌套对象进行分组

如果分组的对象应包含嵌套的序列,就可以改变select子句创建的匿名类型。先看下面的代码:

            var countrys =
from r in Formula1.GetChampions()
group r by r.Country into g //g是?按恪?照?国ú别纄分?组哩?后ó的?Formula1.GetChampions()
orderby g.Count() descending, g.Key //g.Key指?的?是?分?组哩?依皑?据Yr.Country 即′r中D的?Country
where g.Count() >= 2
select
new
{
Country = g.Key,
Count = g.Count(),
Racer = from r1 in g
orderby r1.LastName
select r1.FirstName + " " + r1.LastName
};

 

在上面的例子中,返回的国家不仅包含国家名和赛手数量这两个属性,还包括赛手姓名序列。这个序列用一个赋予Racers属性的from/in内部子句指定,内部的from子句使用分组标识符g获取该分组中的所有赛车手,并排序,再根据姓名创建一个新的字符串返回。

这段代码转换成扩展方法可表示如下:

            var countrys = Formula1.GetChampions()
.GroupBy(r => r.Country)
.OrderByDescending(g => g.Count())
.ThenBy(g => g.Key)
.Where(g => g.Count() >= 2)
.Select(g => new
{
Country = g.Key,
Count = g.Count(),
Racer = g.OrderBy(r => r.LastName).Select(r => r.FirstName + " " + r.LastName)
});

 

       8、连接查询

使用join子句可以根据特定的条件合并两个数据源,但之前要获得两个要连接的列表。

在一级方程式比赛中,有比赛冠军和车队冠军,下边的代码用来筛选出每年的赛手冠军和车队冠军。实现这一功能有几种方法,下面一一列举:

(1)使用多次查询

先定义两个查询,分别找出2003年之后每年的赛手冠军和车队冠军:

//1、查询1
 var racer = from r in Formula1.GetChampions()
from y in r.Years
where y > 2003
select new
{
Year = y,
Name = r.FirstName + " " + r.LastName
};

//2、查询2
 var teams = from t in Formula1.GetConstructorChampions()
from y in t.Years
where y > 2003
select new
{
Year = y,
Name = t.Name
};

之后在通过join in …on…进行连接:

//3、将两次查询结果连接
var query = from r in racer
join t in teams on r.Year equals t.Year
select new
{
Year = r.Year,
Racer = r.Name,
Team = t.Name
};

(2)也可将两次查询合并为一个Linq查询 ,不过比较麻烦的说:

//使用一条语句完成所有连接查询
var query2 = from r in
from
r1 in Formula1.GetChampions()
from yr in r1.Years
where yr > 2003
select new
{
Year = yr,
Name = r1.FirstName + " " + r1.LastName
}
join t in
from
t1 in Formula1.GetConstructorChampions()
from yt in t1.Years
where yt > 2003
select new
{
Year = yt,
Name = t1.Name
}
on r.Year equals t.Year
select new
{
Year = r.Year,
Racer = r.Name,
Team = t.Name
};

       9、集合查询

System.Linq中的扩展方法Distinct()、Union()、Intersect()、Except()的都是集合操作的方法。这些方法使用不难,主要涉及到一些对集合操作的理解上。

下面用一段代码演示集合操作符的使用:

//1、先进性一次简单的查询
var query = from r in Formula1.GetChampions()
from y in r.Years
where y > 2003
select r;
//2、再对结果进行集合操作.这里的几个操作没有实际意义,只是为了演示用法。
 var q = query.Union(query).Distinct().Intersect(query);

上面的代码中,先进行了一个间的的查询,之后对查询结果进行了集合操作。以下是上面代码转换成使用扩展方法的代码:

 //3、直接使用扩展方法进行查询
var query2 = Formula1.GetChampions()
.SelectMany(r => r.Years, (r, y) => new { Racer = r, Year = y }) //使用了SelectMany()嵌套查询
.Where(r => r.Year > 2003)
.Select(r => r.Racer)
.Union(query).Distinct().Intersect(query); //仅演示,没实际意义

       10、合并

合并操作Zip()是.NET4新增的。这个操作运行用一个谓词函数把两个相关的序列合并为一个。我不是很理解这个合并操作,仅给出树上的代码,不做解释:

var racerNames = from r in Formula1.GetChampions()
where r.Country == "Italy"
orderby r.Wins descending
select new
{
Name = r.FirstName + " " + r.LastName
};
var racerNameAndStarts = from r in Formula1.GetChampions()
where r.Country == "Italy"
orderby r.Wins descending
select new
{
LastName = r.LastName,
Starts = r.Starts
};
//.Net4中的Zip()方法。用一个谓词函数把两个相关的序列合并为一个。注意Zip的参数
var racers = racerNames.Zip(racerNameAndStarts, (first, second) => first.Name + ",starts " + second.Starts);
foreach (var item in racers)
{
Console.WriteLine(item);
}

 

       11、分区

扩展方法Take()和Skip()等用于分区操作,这些操作可用于数据分页。在下面的Linq查询中,把扩展方法添加到查询最后,Skip()方法或略掉根据分页大小和页数得到的项数,Take()方法根据分页大小提取一定数目的项:

int pagesize = 5;
int numberPages = (int)Math.Ceiling(Formula1.GetChampions().Count / (double)pagesize);
for (int i = 0; i < numberPages; i++)
{
Console.WriteLine("Page {0}", i);
var racers = (from r in Formula1.GetChampions()
orderby r.LastName
select r.FirstName + " " + r.LastName)
.Skip(i * pagesize) //跳?过y指?定¨数y目?的?元a素?
.Take(pagesize) //提á取?指?定¨数y目?的?元a素?
.TakeWhile(r => r.Length > 11); //额?外a的?限T制?条?件t
foreach (var item in racers)
{
Console.WriteLine(item);
}
Console.WriteLine();

输出结果是几组赛手。

       12、聚合操作

聚合操作用于对集合项进行简单的运算,返回结果是一个值而不是一组数据。

下面演示使用Count()方法筛选出冠军次数操作3的赛手:

//统计获得冠军次数大于3次的运动员和获胜次数
var query = from r in Formula1.GetChampions()
where r.Years.Count() > 3
orderby r.Years.Count() descending
select new
{
Name = r.FirstName + " " + r.LastName,
TimesChampion = r.Years.Count()
};
foreach (var item in query)
{
Console.WriteLine(item.Name + " " + item.TimesChampion.ToString());
}
Console.WriteLine();

又如Sum()方法,返回序列中的所有数字的和。下面的示例演示了使用Sum()方法计算一个国际赢得的比赛次数,首先根据国家对赛手分组,在创建的匿名类中,对Wins属性进行计算:

//计算一个国际获得冠军的总次数
var countries =
from c in
from
r in Formula1.GetChampions()
group r by r.Country into c1
select new
{
Country = c1.Key,
Wins = (from r1 in c1 select r1.Wins).Sum()
}
orderby c.Wins descending
select
c;

       13、结果转换

查询结果可以通过调用扩展方法转换成其他类型。但是需要注意的是,如果进行了类型转换,Linq查询将会立即执行而不是推迟到访问数据项时才执行。

下面是一个简单的例子:

//简单查询
var query = (from r in Formula1.GetChampions()
where r.Starts > 150
orderby r.Starts descending
select
r).ToList();
foreach (var item in query)
{
Console.WriteLine("{0} {0:S}",item);
}
Console.WriteLine();

//扩展方法查询
var query2 = Formula1.GetChampions()
.Where(r => r.Starts > 150)
.OrderByDescending(r => r.Starts)
.ToList()
.Select(r => r) ;
foreach (var item in query2)
{
Console.WriteLine("{0} {0:S}", item);
}
Console.WriteLine();
//生成查找表
var query3 = (from r in Formula1.GetChampions()
from c in r.Cars
select new { Car = c, Racer = r })
.ToLookup(cr => cr.Car, cr => cr.Racer);
if (query3.Contains("Williams"))
{
foreach (var item in query3["Williams"])
{
Console.WriteLine(item);
}
}

这里建查询结果使用ToList()方法转换成了List<T>类型。

       14、生成操作符

生成操作符Ranger()、Empty()、Repear()不是扩展方法,而是返回序列的正常静态方法。

下面例子返回一个填充了一个范围数字的变量,使用了Ranger()方法对变量进行填充

//var values = Enumerable.Range(1, 12);
var values = Enumerable.Range(1, 12)
.Where(r=>r%2 == 0)
.Select(r => r * 2);
foreach (var item in values)
{
Console.Write("{0} ",item);
}
Console.WriteLine();

       15、并行Linq

并行Linq是.Net4新增加的。在.Net 4的System.Linq命名空间中新增加了类ParallelEnumerable,可以分解查询工作使其工作在多个线程上。

这里首先准备一个大型集合,用随机数填充之后使用Linq筛选数据,获取筛选数据的总和。该查询使用where子句定义一个筛选器,汇总值小于20的项,最后使用Sum()方法计算: 

const int arraySize = 100000000;
var data = new int[arraySize];
var r = new Random();
for (int i = 0; i < arraySize; i++)
{
data[i] = r.Next(40);
}
var sum = (from x in data.AsParallel()
where arraySize < 20
select x).Sum();
sum = data.AsParallel().Where(x => x > 20).Select(x => x).Sum();
Console.WriteLine(sum);

可以看出,这里的查询与前面的查询仅仅是使用了AsParallel()方法。

运行这段代码时启动任务管理器就可以看见效果了。此时系统上所有的CPU都处于忙碌状态,如果删除了AsParallel方法,就不会有这个效果了。

 

终于写完了,最后感谢你看了我的文字并附上本文所用的代码:

https://files.cnblogs.com/zyqgold/MyLinqTest.rar

Linq

相关文章: