标准查询操作符就是可以查询任何.NET数组或者集合的API,这个API由System.Query.Sequence静态类中声明的方法组成。标准查询操作符遵守.NET 2.0通用语言规范并且可以用于任何支持范型的.NET编程语言。标准查询操作符可以操作所有实现了IEnumerable<T>接口的对象。
我们将采用一个假设使用场景为学校的示例来讲解标准查询操作符的使用。我们假设有这样几个类:
1: /// <summary>
2: /// The data class of school.
3: /// </summary>
4: public class SchoolData
5: {
6: private int _id = -1;
7: public int ID
8: {
9: get { return this._id; }
10: set { this._id = value; }
11: }
12:
13: private string _name = String.Empty;
14: public string Name
15: {
16: get { return this._name; }
17: set { this._name = value; }
18: }
19:
20: private string _location = String.Empty;
21: public string Location
22: {
23: get { return this._location; }
24: set { this._location = value; }
25: }
26:
27: private string _zipCode = String.Empty;
28: public string ZipCode
29: {
30: get { return this._zipCode; }
31: set { this._zipCode = value; }
32: }
33:
34: private List<StudentData> _students = null;
35: public List<StudentData> Students
36: {
37: get { return ((this._students == null) ? this._students = new List<StudentData>() : this._students); }
38: }
39: }
40:
41: /// <summary>
42: /// The data class of student.
43: /// </summary>
44: public class StudentData
45: {
46: private int _id = -1;
47: public int ID
48: {
49: get { return this._id; }
50: set { this._id = value; }
51: }
52:
53: private string _name = String.Empty;
54: public string Name
55: {
56: get { return this._name; }
57: set { this._name = value; }
58: }
59:
60: private int _age = 0;
61: public int Age
62: {
63: get { return this._age; }
64: set { this._age = value; }
65: }
66:
67: private ScoreData _scores = null;
68: public ScoreData Scores
69: {
70: get { return this._scores; }
71: set { this._scores = value; }
72: }
73: }
74:
75: /// <summary>
76: /// The data class of score.
77: /// </summary>
78: public class ScoreData
79: {
80: private int _chinese = 0;
81: public int Chinese
82: {
83: get { return this._chinese; }
84: set { this._chinese = value; }
85: }
86:
87: private int _math = 0;
88: public int Math
89: {
90: get { return this._math; }
91: set { this._math = value; }
92: }
93:
94: private int _english = 0;
95: public int English
96: {
97: get { return this._english; }
98: set { this._english = value; }
99: }
100: }
我们先给出将要用到的这几个数据类,现在我们得为我们的例子准备点儿原始数据:
1: SchoolData redStarSchool
2: = new SchoolData {
3: ID = 1,
4: Name = "Red Star School",
5: Location = "Red Star Road, Beijing, China.",
6: ZipCode = "100000" };
7: redStarSchool.Students.Add(
8: new StudentData { ID = 1,
9: Name = "ZeroCool",
10: Age = 24,
11: Scores = new ScoreData { Chinese = 88, Math = 91, English = 93 } });
12: redStarSchool.Students.Add(
13: new StudentData {
14: ID = 2,
15: Name = "Frieda",
16: Age = 22,
17: Scores = new ScoreData { Chinese = 94, Math = 97, English = 96 } });
18: redStarSchool.Students.Add(
19: new StudentData {
20: ID = 3,
21: Name = "Michael",
22: Age = 23,
23: Scores = new ScoreData { Chinese = 67, Math = 74, English = 58 } });
好了,我们实例化了一个学校数据类示例,三个学生数据类示例(略去了班级和年级的概念)以及每个学生的三门成绩。原料已经有了,接下来我们看看怎么用这些相同的原料做出不同的菜肴来吧。
首先,我们要介绍几个最基本的查询操作符:
1: from student in redStarSchool.Students
1: where student.Name == "ZeroCool"
1: select student;
其实细心的朋友肯定已经发现了,上面三个关键字的示例代码连起来就正好是一句完整的查询表达式了:
1: IEnumerable<StudentData> students = from student in redStarSchool.Students
2: where student.Name == "ZeroCool"
3: select student;
这样,我们就从redStarSchool数据对象中找到了一个名为“ZeroCool”的学生的数据对象实例。至于你想用Func<TResult>委托类型或是扩展方法结合Lambda表达式的形式来翻译这段查询表达式也无所谓,关键是弄清楚查询操作符的含义与作用就行。上面的代码等效于:
1: // Using extension method.
2: IEnumerable<StudentData> students = redStarSchool.Students.Where(student => student.Name == "ZeroCool").Select(student => student);
3:
4: // Using Func<TResult>.
5: Func<StudentData, bool> filter = student => student.Name == "ZeroCool";
6: Func<StudentData, StudentData> result = student => student;
7:
8: IEnumerable<StudentData> students = redStarSchool.Students.Where(filter).Select(result);
接下来我们将会把精力主要放在介绍标准查询操作符而不是语法上,对语法还不太熟悉的朋友可以参考《C# 3.0 探索之旅》。
1: IEnumerable<StudentData> students = from student in redStarSchool.Students
2: where student.Age <= 23
3: orderby student.Age descending
4: select student;
5:
6: // The declaration above is equivalent to:
7: IEnumerable<StudentData> students
8: = redStarSchool.Students.Where(student => student.Age <= 23).OrderByDescending(student => student.Age).Select(student => student);
1: IEnumerable<StudentData> students
2: = redStarSchool.Students
3: .Where(student => student.Age <= 23)
4: .OrderByDescending(student => student.Age)
5: .Take(1)
6: .Select(student => student);
1: IEnumerable<StudentData> students
2: = redStarSchool.Students
3: .Where(student => student.Age <= 23)
4: .OrderByDescending(student => student.Age)
5: .Skip(1)
6: .Select(student => student);
1: IEnumerable<StudentData> students
2: = redStarSchool.Students
3: .Where(student => student.Age <= 23)
4: .OrderByDescending(student => student.Age)
5: .TakeWhile(student => student.Scores.English < 60)
6: .Select(student => student);
1: IEnumerable<StudentData> students
2: = redStarSchool.Students
3: .Where(student => student.Age <= 23)
4: .OrderByDescending(student => student.Age)
5: .SkipWhile(student => student.Scores.English > 60)
6: .Select(student => student);
1: var students = redStarSchool.Students
2: .Join(redStarSchool.Students,
3: student => student.Age > 21,
4: score => score.Scores.English > 60,
5: (student, score) => new { student.Name, score.Scores.English });
1: var students = redStarSchool.Students
2: .GroupJoin(redStarSchool.Students,
3: student => student.Age < 24,
4: score => score.Scores.English > 60,
5: (student, score) => new { student.Name, count = score.Sum(s => s.Scores.English) });
1: IEnumerable<string> studentNames = redStarSchool.Students
2: .Select(student => student.ID.ToString())
3: .Concat(redStarSchool.Students.Select(student => student.Name));
1: IEnumerable<StudentData> students = redStarSchool.Students
2: .Where(student => student.Age > 18)
3: .OrderBy(student => student.Age)
4: .ThenBy(student => student.Scores.Chinese);
1: IEnumerable<StudentData> students = redStarSchool.Students
2: .Where(student => student.Age > 18)
3: .OrderBy(student => student.Age)
4: .Reverse();
1: var students = redStarSchool.Students
2: .GroupBy(student => student.Scores.English > 60);
1: var students = redStarSchool.Students
2: .Select(student => student.Age)
3: .Distinct();
1: var students = redStarSchool.Students
2: .Where(student => student.Age < 24)
3: .Select(student => student)
4: .Union(redStarSchool.Students.Where(student => student.Age == 24).Select(student => student));
1: var students = redStarSchool.Students
2: .Where(student => student.Age < 24)
3: .Select(student => student)
4: .Intersect(redStarSchool.Students.Where(student => student.Age < 23).Select(student => student));
1: var students = redStarSchool.Students
2: .Where(student => student.Age < 24)
3: .Select(student => student)
4: .Except(redStarSchool.Students.Where(student => student.Age < 23).Select(student => student));
1: var students = redStarSchool.Students
2: .AsEnumerable()
3: .Where(student => student.Age >= 23)
4: .Select(student => student.Name);
1: var students = redStarSchool.Students
2: .Where(student => student.Age >= 23)
3: .Select(student => student.Name)
4: .ToArray();
1: var students = redStarSchool.Students
2: .Where(student => student.Age >= 23)
3: .Select(student => student.Name)
4: .ToArray();
1: var students = redStarSchool.Students
2: .Where(student => student.Age >= 23)
3: .Select(student => student.Name)
4: .ToDictionary(student => student.ToCharArray()[0]);
1: var students = redStarSchool.Students
2: .Join(redStarSchool.Students, name => name.Name == "ZeroCool", age => age.Age == 22, (student, age) => new { student.Name, age.Age })
3: .ToLookup(name => "ZeroCool");
1: var students = redStarSchool.Students
2: .OfType<StudentData>();
1: var students = redStarSchool.Students
2: .Select(student => student.Age)
3: .Cast<double>();
1: var students = redStarSchool.Students
2: .Where(student => student.Age > 23)
3: .Select(student => student)
4: .SequenceEqual(redStarSchool.Students.Where(student => student.Age < 23).Select(student => student));
1: var student = redStarSchool.Students
2: .Where(classmate => classmate.Age < 24)
3: .Select(classmate => classmate)
4: .First();
1: var student = redStarSchool.Students
2: .Where(classmate => classmate.Age > 24)
3: .Select(classmate => classmate)
4: .FirstOrDefault();
1: var student = redStarSchool.Students
2: .Where(classmate => classmate.Age < 24)
3: .Select(classmate => classmate)
4: .Last();
1: var student = redStarSchool.Students
2: .Where(classmate => classmate.Age > 24)
3: .Select(classmate => classmate)
4: .LastOrDefault();
1: var student = redStarSchool.Students
2: .Where(classmate => classmate.Age < 24)
3: .Single(classmate => classmate.Name.Length == 6);
1: var student = redStarSchool.Students
2: .Where(classmate => classmate.Age > 24)
3: .SingleOrDefault(classmate => classmate.Name == "ZeroCool");
1: var students = redStarSchool.Students
2: .Select(student => student)
3: .ElementAt(1);
1: var students = redStarSchool.Students
2: .Select(student => student)
3: .ElementAtOrDefault(5);
1: var students = redStarSchool.Students
2: .Where(student => student.Age > 25)
3: .Select(student => student.Name)
4: .DefaultIfEmpty();
1: var range = Enumerable.Range(0, 100);
1: var range = Enumerable.Repeat(1, 100);
1: var range = Enumerable.Empty<Int32>();
1: bool hasFailedStudent = redStarSchool.Students
2: .Any(student => student.Scores.Chinese < 60 || student.Scores.Math < 60 || student.Scores.English < 60);
1: bool allSucceed = redStarSchool.Students
2: .All(student => student.Scores.Chinese >= 60 && student.Scores.Math >= 60 && student.Scores.English >= 60);
1: bool zerocoolExists = redStarSchool.Students
2: .Where(student => student.Age <= 24)
3: .Select(student => student.Name)
4: .Contains("ZeroCool");
1: int englishSucceedAmount = redStarSchool.Students
2: .Count(student => student.Scores.English > 60);
1: long studentAmount = redStarSchool.Students.LongCount();
1: int englishScoreTotal = redStarSchool.Students
2: .Sum(englishScore => englishScore.Scores.English);
1: int lowestEnglishScore = redStarSchool.Students
2: .Min(englishScore => englishScore.Scores.English);
1: int highestEnglishScore = redStarSchool.Students
2: .Max(englishScore => englishScore.Scores.English);
1: double averageEnglishScore = redStarSchool.Students
2: .Average(englishScore => englishScore.Scores.English);
1: int youngerStudentAmount = redStarSchool.Students
2: .Select(age => age.Age)
3: .Aggregate(21, (ageA, ageB) => ageA >= ageB ? ageA : ageB);
标准查询操作符就介绍到这里了,我相信各位朋友看了这篇文章中的介绍都已经领略到了LINQ的强大与适用,相信各位朋友通过实际动手练习,很快就能轻松自如地编写查询语句,并从中获得美妙的开发体验!