標準查詢運算符概觀
標準查詢運算符 是構成 LINQ 模式的關鍵詞和方法。 C# 語言會定義 LINQ 查詢關鍵字, 以便用於最常見的查詢語法。 編譯程式會使用這些關鍵詞將表達式轉譯為對等的方法呼叫。 這兩種形式是同義字。 屬於 System.Linq 命名空間的其他方法沒有對等的查詢關鍵詞。 在這些情況下,您必須使用方法語法。 本節涵蓋所有查詢運算符關鍵詞。 執行階段和其他 NuGet 套件在每次版本更新中都會新增更多方法,這些方法專門用於配合 LINQ 查詢。 本節涵蓋最常見的方法,包括那些具有查詢關鍵詞等同詞的方法。 如需 .NET 運行時間所支援之查詢方法的完整清單,請參閱 System.Linq.Enumerable API 檔。 除了這裡所涵蓋的方法之外,這個類別還包含串連數據源的方法、從數據源計算單一值,例如總和、平均值或其他值。
這很重要
這些範例會使用 System.Collections.Generic.IEnumerable<T> 資料來源。 根據 System.Linq.IQueryProvider 的資料來源會使用 System.Linq.IQueryable<T> 資料來源和運算式樹。 運算式樹在允許的 C# 語法方面有限制。 此外,每個 IQueryProvider
資料來源 (例如 EF Core) 可能會施加更多限制。 檢查資料來源的文件。
這些方法大多在序列上運作,其中序列是物件,其類型會實作 IEnumerable<T> 介面或 IQueryable<T> 介面。 標準查詢運算子提供查詢功能,包括篩選、投影、匯總、排序等等。 組成每個集合的方法分別是 Enumerable 和 Queryable 類別的靜態成員。 它們定義為 擴充方法, 其運作的類型。
IEnumerable<T> 與 IQueryable<T> 序列之間的差異會決定查詢在運行時間的執行方式。
針對IEnumerable<T>
,傳回的可列舉物件會擷取傳遞至方法的參數。 列舉該物件時,會採用查詢運算子的邏輯,並傳回查詢結果。
對於 IQueryable<T>
,查詢被轉換為 的表達式樹狀結構。 當數據源可以優化查詢時,表達式樹狀結構可以轉譯為原生查詢。
Entity Framework 之類的連結庫 將 LINQ 查詢轉譯為在資料庫執行的原生 SQL 查詢。
下列程式代碼範例示範如何使用標準查詢運算符來取得序列的相關信息。
string sentence = "the quick brown fox jumps over the lazy dog";
// Split the string into individual words to create a collection.
string[] words = sentence.Split(' ');
// Using query expression syntax.
var query = from word in words
group word.ToUpper() by word.Length into gr
orderby gr.Key
select new { Length = gr.Key, Words = gr };
// Using method-based query syntax.
var query2 = words.
GroupBy(w => w.Length, w => w.ToUpper()).
Select(g => new { Length = g.Key, Words = g }).
OrderBy(o => o.Length);
foreach (var obj in query)
{
Console.WriteLine($"Words of length {obj.Length}:");
foreach (string word in obj.Words)
Console.WriteLine(word);
}
// This code example produces the following output:
//
// Words of length 3:
// THE
// FOX
// THE
// DOG
// Words of length 4:
// OVER
// LAZY
// Words of length 5:
// QUICK
// BROWN
// JUMPS
可能的話,本節中的查詢會使用一連串的單字或數位作為輸入來源。 對於使用對象之間較複雜關聯性的查詢,會使用下列建立學校模型的來源:
public enum GradeLevel
{
FirstYear = 1,
SecondYear,
ThirdYear,
FourthYear
};
public class Student
{
public required string FirstName { get; init; }
public required string LastName { get; init; }
public required int ID { get; init; }
public required GradeLevel Year { get; init; }
public required List<int> Scores { get; init; }
public required int DepartmentID { get; init; }
}
public class Teacher
{
public required string First { get; init; }
public required string Last { get; init; }
public required int ID { get; init; }
public required string City { get; init; }
}
public class Department
{
public required string Name { get; init; }
public int ID { get; init; }
public required int TeacherID { get; init; }
}
每個 Student
都有一個等級、一個主要部門和一系列分數。
Teacher
也有一個 City
屬性,可識別教師持有課程的校園。
Department
具有名稱,以及對擔任部門負責人的 Teacher
的參考。
您可以在 來源存放庫中找到資料集,。
查詢運算子的類型
標準查詢運算符的執行時間會因傳回單一值或值序列而有所不同。 傳回單一值的方法(例如 Average 和 Sum)會立即執行。 傳回序列的方法會延遲查詢執行,並傳回可列舉的物件。 您可以使用查詢的輸出序列做為另一個查詢的輸入序列。 查詢方法的呼叫可以在一個查詢中鏈結在一起,讓查詢變得任意複雜。
查詢運算子
在 LINQ 查詢中,第一個步驟是指定數據源。 在 LINQ 查詢中,from
子句先行引進數據源(students
)和 範圍變數(student
)。
//queryAllStudents is an IEnumerable<Student>
var queryAllStudents = from student in students
select student;
範圍變數就像 foreach
迴圈中的迭代變數,而在查詢表達式中不會發生實際的迭代。 執行查詢時,範圍變數會做為 students
中每個後續項目的參考。 因為編譯程式可以推斷 student
的類型,所以您不需要明確指定它。 您可以在 let
子句中引進更多範圍變數。 如需詳細資訊,請參閱 let 子句。
備註
對於非泛型數據源,例如 ArrayList,範圍變數必須明確輸入。 如需詳細資訊,請參閱 如何使用 LINQ 查詢 ArrayList (C#) 和 from 子句。
取得數據源之後,您就可以在該數據源上執行任意數目的作業:
-
使用
where
關鍵詞篩選數據。 -
使用
orderby
和選擇性地descending
關鍵詞來排序數據。 -
使用
group
和選擇性地into
關鍵詞群組數據。 -
使用
join
關鍵詞聯結數據。 - 使用
select
關鍵詞處理 專案 的數據。
查詢表達式語法數據表
下表列出具有對等查詢表達式子句的標準查詢運算符。
使用 LINQ 進行資料轉換
Language-Integrated 查詢 (LINQ) 不只與擷取數據有關。 它也是轉換數據的強大工具。 藉由使用 LINQ 查詢,您可以使用來源序列做為輸入,並以許多方式修改它,以建立新的輸出序列。 您可以藉由排序和分組來修改序列本身,而不需要修改元素本身。 但是,LINQ 查詢最強大的功能或許是建立新類型的能力。 select 子句會從輸入元素建立輸出元素。 您可以使用它,將輸入元素轉換成輸出元素:
- 將多個輸入序列合併成具有新類型的單一輸出序列。
- 建立輸出序列,其元素只包含來源序列中元素的一或多個屬性。
- 建立輸出序列,其元素由對源數據進行操作的結果組成。
- 以不同的格式建立輸出序列。 例如,您可以將 SQL 資料列或文字檔中的數據轉換成 XML。
這些轉換可以在相同查詢中以各種方式合併。 此外,一個查詢的輸出順序可以做為新查詢的輸入順序。 下列範例會將記憶體內部數據結構中的物件轉換成 XML 元素。
// Create the query.
var studentsToXML = new XElement("Root",
from student in students
let scores = string.Join(",", student.Scores)
select new XElement("student",
new XElement("First", student.FirstName),
new XElement("Last", student.LastName),
new XElement("Scores", scores)
) // end "student"
); // end "Root"
// Execute the query.
Console.WriteLine(studentsToXML);
程式代碼會產生下列 XML 輸出:
<Root>
<student>
<First>Svetlana</First>
<Last>Omelchenko</Last>
<Scores>97,90,73,54</Scores>
</student>
<student>
<First>Claire</First>
<Last>O'Donnell</Last>
<Scores>56,78,95,95</Scores>
</student>
...
<student>
<First>Max</First>
<Last>Lindgren</Last>
<Scores>86,88,96,63</Scores>
</student>
<student>
<First>Arina</First>
<Last>Ivanova</Last>
<Scores>93,63,70,80</Scores>
</student>
</Root>
如需詳細資訊,請參閱 在 C# 中建立 XML 樹狀結構 (LINQ to XML)。
您可以使用一個查詢的結果作為後續查詢的數據源。 這個範例示範如何排序聯結作業的結果。 此查詢會建立群組聯接,然後根據仍在範圍內的類別元素來排序群組。 在匿名型別初始化器內,子查詢會排序產品序列中的所有相符元素。
var orderedQuery = from department in departments
join student in students on department.ID equals student.DepartmentID into studentGroup
orderby department.Name
select new
{
DepartmentName = department.Name,
Students = from student in studentGroup
orderby student.LastName
select student
};
foreach (var departmentList in orderedQuery)
{
Console.WriteLine(departmentList.DepartmentName);
foreach (var student in departmentList.Students)
{
Console.WriteLine($" {student.LastName,-10} {student.FirstName,-10}");
}
}
/* Output:
Chemistry
Balzan Josephine
Fakhouri Fadi
Popov Innocenty
Seleznyova Sofiya
Vella Carmen
Economics
Adams Terry
Adaobi Izuchukwu
Berggren Jeanette
Garcia Cesar
Ifeoma Nwanneka
Jamuike Ifeanacho
Larsson Naima
Svensson Noel
Ugomma Ifunanya
Engineering
Axelsson Erik
Berg Veronika
Engström Nancy
Hicks Cassie
Keever Bruce
Micallef Nicholas
Mortensen Sven
Nilsson Erna
Tucker Michael
Yermolayeva Anna
English
Andersson Sarah
Feng Hanying
Ivanova Arina
Jakobsson Jesper
Jensen Christiane
Johansson Mark
Kolpakova Nadezhda
Omelchenko Svetlana
Urquhart Donald
Mathematics
Frost Gaby
Garcia Hugo
Hedlund Anna
Kovaleva Katerina
Lindgren Max
Maslova Evgeniya
Olsson Ruth
Sammut Maria
Sazonova Anastasiya
Physics
Åkesson Sami
Edwards Amy E.
Falzon John
Garcia Debra
Hansson Sanna
Mattsson Martina
Richardson Don
Zabokritski Eugene
*/
使用方法語法的對等查詢會顯示在下列程式碼中:
var orderedQuery = departments
.GroupJoin(students, department => department.ID, student => student.DepartmentID,
(department, studentGroup) => new
{
DepartmentName = department.Name,
Students = studentGroup.OrderBy(student => student.LastName)
})
.OrderBy(department => department.DepartmentName);
foreach (var departmentList in orderedQuery)
{
Console.WriteLine(departmentList.DepartmentName);
foreach (var student in departmentList.Students)
{
Console.WriteLine($" {student.LastName,-10} {student.FirstName,-10}");
}
}
雖然在聯結之前可以使用 orderby
子句來搭配一或多個來源序列,但一般我們不建議這麼做。 某些 LINQ 提供者可能不會在聯結之後保留該順序。 如需詳細資訊,請參閱 join 子句。