Effective C# 30.偏好查詢語法而非迴圈 Effective C# 30.偏好查詢語法而非迴圈 (Prefer Query Syntax to Loops)

Published on Monday, October 21, 2024

這個做法建議使用 Query Syntax 取代 forwhiledo/whileforeach 等傳統迴圈。

例如下面這段就是使用 query expression 的一段範例程式碼。

var foo = (from n in Enumerable.Range(0, 100)
			   select n * n).ToArray();

與傳統的迴圈相比使用 query expression 的寫法比較簡單而且可以一眼看懂。

var foo = new int[100];
 for (var num = 0; num < foo.Length; num++)
    foo[num] = num * num;
 foreach (int i in foo)
    Console.WriteLine(i.ToString());

在簡單的方法中可能沒什麼感覺,但是在複雜一點的方法就能看出使用 query expression 表達程式碼意圖比較明確, 而一般的迴圈要達到同樣的效果會比較難懂。

private static IEnumerable<Tuple<int, int>> ProduceIndices3()
{
	var storage = new List<Tuple<int, int>>();
	for (var x = 0; x < 100; x++)
		for (var y = 0; y < 100; y++)
			if (x + y < 100)
				storage.Add(Tuple.Create(x, y));
	storage.Sort((point1, point2) =>
		(point2.Item1 * point2.Item1 + point2.Item2 *
		point2.Item2).CompareTo(
		point1.Item1 * point1.Item1 + point1.Item2 *
		point1.Item2));
	return storage;
}

private static IEnumerable<Tuple<int, int>> QueryIndices3()
{
	return from x in Enumerable.Range(0, 100)
		   from y in Enumerable.Range(0, 100)
		   where x + y < 100
		   orderby (x * x + y * y) descending
		   select Tuple.Create(x, y);
}

基本上每個 Query Syntax 的寫法都有對應的 Method Call Syntax,基本上就是擴充方法搭配 Lambda 語法的呼叫方式, 要選擇哪一種寫法可以按情況而定,例如在使用 EFCore 讀取資料表時使用 query expression 會比較貼近原始 SQL。

private static IEnumerable<Tuple<int, int>> MethodIndices3()
{
    return Enumerable.Range(0, 100).
        SelectMany(x => Enumerable.Range(0,100),
        (x,y) => Tuple.Create(x,y)).
        Where(pt => pt.Item1 + pt.Item2 < 100).
        OrderByDescending(pt =>
            pt.Item1* pt.Item1 + pt.Item2 * pt.Item2);
}

Summary

這個做法就是在推薦使用 Query Syntax 或是 Method Call Syntax 這兩種新的 LINQ 寫法,可以按照自己或公司的規範看看是否要月來取代傳統迴圈。