支援 LINQ 的 C# 功能

查詢運算式

查詢運算式使用類似 SQL 或 XQuery 的宣告式語法來查詢 System.Collections.Generic.IEnumerable<T> 集合。 在編譯時間,查詢語法會轉換成對 LINQ 提供者實作的標準查詢方法進行的方法呼叫。 應用程式使用 using 指示詞來指定適當的命名空間,藉此控制範圍內的標準查詢運算子。 下列查詢運算式會擷取字串的陣列,然後根據字串的第一個字元分組字串,再排序這些群組。

var query = from str in stringArray
            group str by str[0] into stringGroup
            orderby stringGroup.Key
            select stringGroup;

隱含型別變數 (var)

您可以使用 var 修飾元來指示編譯程式推斷並指派類型,如下所示:

var number = 5;
var name = "Virginia";
var query = from str in stringArray
            where str[0] == 'm'
            select str;

宣告為 var 的變數和明確指定類型的變數一樣具有強型別。 var 可用來建立匿名型別,但僅適用於區域變數。 如需詳細資訊,請參閱隱含型別區域變數

物件和集合初始設定式

物件和集合初始設定式可以初始化物件,而不需要明確呼叫物件的建構函式。 初始設定式通常會用於將來源資料投影為新資料類型的查詢運算式中。 假設有個名為 Customer 的類別具有公用的 NamePhone 屬性,則可如下列程式碼所示使用物件初始設定式:

var cust = new Customer { Name = "Mike", Phone = "555-1212" };

延續我們的 Customer 類別,假設有一個稱為 IncomingOrders 的資料來源,而其每個訂單都有大型的 OrderSize,您想要根據該訂單建立新的 Customer。 您可以針對此資料來源執行 LINQ 查詢,並使用物件初始化來填滿集合:

var newLargeOrderCustomers = from o in IncomingOrders
                            where o.OrderSize > 5
                            select new Customer { Name = o.Name, Phone = o.Phone };

資料來源可能定義了比 Customer 類別更多的屬性 (例如 OrderSize),但使用物件初始化時,從查詢傳回的資料會塑造為我們想要的資料型別;您選擇與您類別相關的資料。 因此,您現在有使用新的 Customer 填滿的 System.Collections.Generic.IEnumerable<T>,這正是您所需要的。 上述範例也可以使用 LINQ 的方法語法撰寫:

var newLargeOrderCustomers = IncomingOrders.Where(x => x.OrderSize > 5).Select(y => new Customer { Name = y.Name, Phone = y.Phone });

從 C# 12 開始,您可以使用集合運算式來初始化集合。

如需詳細資訊,請參閱

匿名類型

編譯程式會建構匿名型別。 型別名稱僅適用於編譯程式。 匿名型別提供了一個便利的方法,暫時將查詢結果中的一組屬性分組,而不需要另外定義具名類型。 匿名型別是以新的運算式和物件初始設定式進行初始化,如下所示:

select new {name = cust.Name, phone = cust.Phone};

從 C# 7 開始,您可以使用 Tuple 來建立未命名的型別。

擴充方法

擴充方法是一種可以與類型相關聯的靜態方法,因此可以像呼叫類型上的執行個體方法一樣呼叫它。 這項功能實際上可讓您「新增」方法至現有的類型,而不需要實際修改這些類型。 標準查詢運算子是一組擴充方法,可為實作 IEnumerable<T> 的任何類型提供 LINQ 查詢功能。

Lambda 運算式

Lambda 運算式是一種內嵌函式,其使用 => 運算子分隔輸入參數與函式主體,而且可以在編譯期間轉換成委派或運算式樹狀架構。 在 LINQ 程式設計中,當您直接對標準查詢運算子進行方法呼叫時,就會遇到 Lambda 運算式。

運算式做為數據

查詢物件是可編寫的,這表示您可以從方法傳回查詢。 代表查詢的物件不會儲存所產生的集合,而是在必要時產生結果的步驟。 從方法傳回查詢物件的優點,在於可以進一步編寫或修改它們。 因此,傳回查詢的方法的任何傳回值或 out 參數也必須具有該類型。 如果方法將查詢具體化到具體 List<T>Array 類型,則會傳回查詢結果,而不是查詢本身。 從方法傳回的查詢變數仍然可以進行編寫或修改。

在下列範例中,第一個方法 QueryMethod1 會以傳回值形式傳回查詢,第二個方法 QueryMethod2 會以 out 參數 (範例中的 returnQ) 形式傳回查詢。 在這兩種情況下,其是傳回的查詢,而不是查詢結果。

IEnumerable<string> QueryMethod1(int[] ints) =>
    from i in ints
    where i > 4
    select i.ToString();

void QueryMethod2(int[] ints, out IEnumerable<string> returnQ) =>
    returnQ =
        from i in ints
        where i < 4
        select i.ToString();

int[] nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

var myQuery1 = QueryMethod1(nums);

查詢 myQuery1 會在下列 foreach 迴圈中執行。

foreach (var s in myQuery1)
{
    Console.WriteLine(s);
}

將滑鼠指標放在 myQuery1 上方以查看其類型。

您也可以直接執行從 QueryMethod1 傳回的查詢,而不使用 myQuery1

foreach (var s in QueryMethod1(nums))
{
    Console.WriteLine(s);
}

將滑鼠指標放在呼叫 QueryMethod1 上方,以查看其傳回類型。

QueryMethod2 會傳回查詢作為其 out 參數的值:

QueryMethod2(nums, out IEnumerable<string> myQuery2);

// Execute the returned query.
foreach (var s in myQuery2)
{
    Console.WriteLine(s);
}

您可以使用查詢組合來修改查詢。 在此情況下,系統會使用先前的查詢物件來建立新的查詢物件。 這個新物件會傳回與原始查詢物件不同的結果。

myQuery1 =
    from item in myQuery1
    orderby item descending
    select item;

// Execute the modified query.
Console.WriteLine("\nResults of executing modified myQuery1:");
foreach (var s in myQuery1)
{
    Console.WriteLine(s);
}