.NET 6 and why should I care?.NET 6 is the upcoming major overhaul for .NET. It unifies entire .NET experience. No more .NET Core, .NET Full Framework, Xamarin, Mono, etc. Just a single .NET.
LINQ FeaturesAt the time of writing this post, 5 previews of .NET 6 have been released and last couple of releases have been blessing for LINQ.
Here are few top new LINQ features:
MaxBy and MinByChunkDistinctBy, UnionBy, IntersectBy, and ExceptByIndex and Range parametersTryGetNonEnumeratedCountFirstOrDefault, LastOrDefault, and SingleOrDefaultZip supports 3 IEnumerablesMaxBy and MinByFinding out maximum or minimum has now been easier than even with these new MaxBy or MinBy methods.
Suppose a List of Persons as:
static List<Person> people = new List<Person>
{
new Person { Id = 1, Name = "Amit", Age = 38},
new Person { Id = 2, Name = "Ravi", Age = 36},
new Person { Id = 3, Name = "Manish", Age = 34},
new Person { Id = 4, Name = "Satish", Age = 29},
};
If we need to get maximum and minimum, currently here’s how to do it:
//Without using MaxBy and MinBy
Person oldestPerson = people.OrderByDescending(person => person.Age).First();
Person youngestPerson = people.OrderBy(person => person.Age).First();
Console.WriteLine($"Oldest Person without using MaxBy: {oldestPerson.Name}");
Console.WriteLine($"Youngest Person without using MaxBy: {youngestPerson.Name}");
But with MaxBy and MinBy, it’s just a single method call:
Person oldestPerson = people.MaxBy(person => person.Age);
Person youngestPerson = people.MinBy(person => person.Age);
Console.WriteLine($"Oldest Person using MaxBy: {oldestPerson.Name}");
Console.WriteLine($"Youngest Person using MaxBy: {youngestPerson.Name}");
Neat, right? Let me know in the comments, if you have alternate methods of getting maximum and minimum using LINQ.
ChunkA new method Chunk slices the IEnumerable into provided sizes. e.g. If you have a collection of 4 elements and you need to cluster them into fixed size of 2, here’s how to do:
IEnumerable<Person[]> cluster = people.Chunk(2);
// Print each cluster.
foreach(var people in cluster)
{
Console.WriteLine($"Cluster of {string.Join(",", people.Select(person => person.Name))}");
}
//Prints
// Cluster of Amit,Ravi
// Cluster of Manish,Satish
DistinctBy, UnionBy, IntersectBy, and ExceptByExisiting set methods Distinct, Union, Intersect, and Except have been powered up by these new methods which can take a selector function to operate.
e.g.
IEnumerable<Person> evenAgedPeople = people.Where(person => person.Age % 2 == 0);
//Amit,Ravi,Manish
IEnumerable<Person> personAbove35 = people.Where(person => person.Age > 35);
//Amit,Ravi
IEnumerable<Person> union = evenAgedPeople.UnionBy(personAbove35, x => x.Age);
//Amit,Ravi,Manish
IEnumerable<Person> intersection = evenAgedPeople.IntersectBy(personAbove35.Select(p => p.Age), x => x.Age);
//Amit,Ravi
Let me know in the comments, the usage of DistinctBy and ExceptBy.
Index and Range parametersRange: .., and Index: ^ already exist in C#8, .NET 6 brings these two to LINQ.
ElementAt operator now takes indices from the end.Person secondLastPerson = people.ElementAt(^2);
//Manish
Skip and Take now take Range as well:
````csharp
IEnumerableIEnumerable
IEnumerable
IEnumerable
IEnumerable
IEnumerable
## New method `TryGetNonEnumeratedCount`
Sometimes you need to get a count without the enumeration. `TryGetNonEnumeratedCount` will try to get count without foring an enumeration. It internally checks for the implementation of `ICollection` i.e. `IEnumerable` that already has a mechanism to get count without forcing an enumeration. Otherwise it'll try to take advantange of new improvements in `LINQ`.
Useful in scenarios where you want to get a count but not at the cost of enumerating the `IEnumerable`.
e.g.
````csharp
List<Person> anotherList = people.TryGetNonEnumeratedCount(out int count) ? new List<Person>(count): new List<Person>();
anotherList.AddRange(people);
In our case right now, we know that people is just an in-memory list, but what if it was from database of some Stream, then it would’ve made sense to find out the count to optimize the instantiation of anotherList object by specifying capacity parameter.
FirstOrDefault, LastOrDefault, and SingleOrDefaultCurrent FirstOrDefault, LastOrDefault, and SingleOrDefault methods return default(T) if the source IEnumerable is empty. The new overloads accept a parameter which will be returned if source is empty.
e.g.
List<int> emptyList = new List<int>();
int value = emptyList.FirstOrDefault(-1);
//-1 instead of 0
This reminds me of ISNULL function of SQL Server.
Zip supports 3 IEnumerablesBefore .NET 6, Zip used to take only 2 parameters. Now it takes 3 parameters:
IEnumerable<int> ids = Enumerable.Range(1, 4);
IEnumerable<Person> allPeople = people;
IEnumerable<int> allAges = people.Select(person => person.Age);
IEnumerable<(int Id, Person Person, int Age)> zipped = ids.Zip(allPeople, allAges);
.NET 6 previews are bring awesome set of new features with every new release. Let me know in comments which all features you’re excited for.
.NET 6 today and try out.Originally posted at: https://blog.satishyadav.com/.net-6-linq-new-features