.NET 6 中 LINQ 的改进

dotNET全栈开发

共 3706字,需浏览 8分钟

 ·

2022-01-02 12:03

原文:bit.ly/32guqbn
作者:Oleg Kyrylchuk
翻译:精致码农-王亮

1*OrDefault 方法的默认值

Enumerable.FirstOrDefault 方法返回一个序列的第一个元素,如果没有找到,则返回一个默认值。在 .NET 6 中,你可以覆盖该方法的默认值。同样,你还可以覆盖 SingleOrDefaultLastOrDefault 方法的默认值。

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 found

2新的 *By 方法

.NET 6 引入了新的 Enumerable.By* 方法,它的 keySelector 参数用来比较元素。这些新方法有:

  • 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 方法

如果你需要将一个序列的元素分割成块,在 .NET 6 中你不必再自己实现了,它引入了一个新的 Enumerable.Chunk 扩展方法。

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...505

4三向 Zip 方法

Enumerable.Zip 扩展方法可以将两个序列进行结合产生产生一个二元组序列。在 .NET 6 中,它可以结合三个序列产生一个三元组序列。

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 Spring

5ElementAt 方法支持 Index

.NET Core 3.0 引入了 Index 结构体,它被 C# 编译器用来支持一个新的前缀“帽子”运算符(^)。它表示“从集合的末端”开始的索引。在 .NET 6 中,Enumerable.ElementAt 方法支持 Index

IEnumerable<int> numbers = new int[] { 1, 2, 3, 4, 5 };
int last = numbers.ElementAt(^0);
Console.WriteLine(last); // 5

6Take 方法支持 Range

.NET Core 3.0 中也引入了 Range 结构体,它被 C# 编译器用来支持一个范围操作符 ...。在 .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
// 5

7TryGetNonEnumeratedCount 避免列举

.NET 6 引入了一个新的 Enumerable.TryGetNonEnumerated 方法,它试图确定一个序列中元素的数量,而不强制进行列举。它对 IQueryable 很有用,当调用 Enumerable.Count 时,你不希望执行整个查询。

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结束语

所有的代码示例你都可以在我的 GitHub 上找到:

https://github.com/okyrylchuk/dotnet6_features/tree/main/LINQ%20imrpovements


浏览 19
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报