.NET 6 中 LINQ 的改進(jìn)
原文:bit.ly/32guqbn
作者:Oleg Kyrylchuk
翻譯:精致碼農(nóng)-王亮
1*OrDefault 方法的默認(rèn)值
Enumerable.FirstOrDefault 方法返回一個(gè)序列的第一個(gè)元素,如果沒有找到,則返回一個(gè)默認(rèn)值。在 .NET 6 中,你可以覆蓋該方法的默認(rèn)值。同樣,你還可以覆蓋 SingleOrDefault 和 LastOrDefault 方法的默認(rèn)值。
List<int> list1 = new() { 1, 2, 3 };
int item1 = list1.FirstOrDefault(i => i == 4, -1);
Console.WriteLine(item1); // -1
List<string> list2 = new() { "Item1" };
string item2 = list2.SingleOrDefault(i => i == "Item2", "Not found");
Console.WriteLine(item2); // Not found2新的 *By 方法
.NET 6 引入了新的 Enumerable.By*?方法,它的?keySelector?參數(shù)用來比較元素。這些新方法有:
MinBy
MaxBy
DistinctBy
ExceptBy
IntersectBy
UnionBy
List products = new()
{
new() { Name = "Product1", Price = 100 },
new() { Name = "Product2", Price = 5 },
new() { Name = "Product3", Price = 50 },
};
Product theCheapestProduct = products.MinBy(x => x.Price);
Product theMostExpensiveProduct = products.MaxBy(x => x.Price);
Console.WriteLine(theCheapestProduct);
// Output: Product { Name = Product2, Price = 5 }
Console.WriteLine(theMostExpensiveProduct);
// Output: Product { Name = Product1, Price = 100 }
record?Product
{
public?string Name { get; set; }
public?decimal Price { get; set; }
} 3新的 Chunk 方法
如果你需要將一個(gè)序列的元素分割成塊,在 .NET 6 中你不必再自己實(shí)現(xiàn)了,它引入了一個(gè)新的 Enumerable.Chunk 擴(kuò)展方法。
IEnumerable<int> numbers = Enumerable.Range(1, 505);
IEnumerable<int[]> chunks = numbers.Chunk(100);
foreach (int[] chunk in chunks)
{
Console.WriteLine($"{chunk.First()}...{chunk.Last()}");
}
// Output:
// 1...100
// 101...200
// 201...300
// 301...400
// 401...500
// 501...5054三向 Zip 方法
Enumerable.Zip?擴(kuò)展方法可以將兩個(gè)序列進(jìn)行結(jié)合產(chǎn)生產(chǎn)生一個(gè)二元組序列。在 .NET 6 中,它可以結(jié)合三個(gè)序列產(chǎn)生一個(gè)三元組序列。
int[] numbers = { 1, 2, 3, 4, };
string[] months = { "Jan", "Feb", "Mar" };
string[] seasons = { "Winter", "Winter", "Spring" };
var test = numbers.Zip(months).Zip(seasons);
foreach ((int, string, string) zipped in numbers.Zip(months, seasons))
{
Console.WriteLine($"{zipped.Item1}?{zipped.Item2}?{zipped.Item3}");
}
// Output:
// 1 Jan Winter
// 2 Feb Winter
// 3 Mar Spring5ElementAt 方法支持 Index
.NET Core 3.0 引入了 Index 結(jié)構(gòu)體,它被 C# 編譯器用來支持一個(gè)新的前綴“帽子”運(yùn)算符(^)。它表示“從集合的末端”開始的索引。在 .NET 6 中,Enumerable.ElementAt 方法支持 Index。
IEnumerable<int> numbers = new?int[] { 1, 2, 3, 4, 5 };
int last = numbers.ElementAt(^0);
Console.WriteLine(last); // 56Take 方法支持 Range
.NET Core 3.0 中也引入了 Range 結(jié)構(gòu)體,它被 C# 編譯器用來支持一個(gè)范圍操作符 ...。在 .NET 6 中,Enumerable.Take 方法也支持 Range。
IEnumerable<int> numbers = new?int[] { 1, 2, 3, 4, 5 };
IEnumerable<int> taken1 = numbers.Take(2..4);
foreach (int i in taken1)
Console.WriteLine(i);
// Output:
// 3
// 4
IEnumerable<int> taken2 = numbers.Take(..3);
foreach (int i in taken2)
Console.WriteLine(i);
// Output:
// 1
// 2
// 3
IEnumerable<int> taken3 = numbers.Take(3..);
foreach (int i in taken3)
Console.WriteLine(i);
// Output:
// 4
// 57用 TryGetNonEnumeratedCount 避免列舉
.NET 6 引入了一個(gè)新的 Enumerable.TryGetNonEnumerated 方法,它試圖確定一個(gè)序列中元素的數(shù)量,而不強(qiáng)制進(jìn)行列舉。它對(duì) IQueryable 很有用,當(dāng)調(diào)用 Enumerable.Count 時(shí),你不希望執(zhí)行整個(gè)查詢。
IEnumerable<int> numbers = GetNumbers();
TryGetNonEnumeratedCount(numbers);
// Output: Could not get a count of numbers without enumerating the sequence
IEnumerable<int> enumeratedNumbers = numbers.ToList();
var test = enumeratedNumbers.ElementAt(-1);
TryGetNonEnumeratedCount(enumeratedNumbers);
// Output: Count: 5
void?TryGetNonEnumeratedCount(IEnumerable<int> numbers)
{
if (numbers.TryGetNonEnumeratedCount(out?int count))
Console.WriteLine($"Count: {count}");
else
Console.WriteLine("Could not get a count of numbers without enumerating the sequence");
}
IEnumerable<int> GetNumbers()
{
yield?return?1;
yield?return?2;
yield?return?3;
yield?return?4;
yield?return?5;
}8結(jié)束語
所有的代碼示例你都可以在我的 GitHub 上找到:
https://github.com/okyrylchuk/dotnet6_features/tree/main/LINQ%20imrpovements