.Net 6 : Les nouveautés de LINQ en un clin d’œil!
Avec l’arrivée de .Net 6, nous pouvons profiter de nouvelles méthodes intéressantes de LINQ. Cet article vous présentera l’ensemble de ces nouveautés, avec un exemple de code pour chacune d’entre elles.
Enumerable.TryGetNonEnumeratedCount
Si vous avez une instance de type Enumerable, je vous conseille d’éviter d’appeler la méthode Count() de celle-ci. Contrairement à la propriété Count d’une liste ou d’une collection, qui retourne directement le nombre d’éléments, la méthode Count() va effectuer une itération de chaque élément pour incrémenter un compteur et retourner ce dernier (Sauf si votre Enumarable peut-être castée en ICollection). Cette méthode a un donc un coût niveau performance.
Une nouvelle méthode, TryGetNonEnumeratedCount a été ajoutée avec le .Net 6. Cette dernière va d’abord tester de comparer votre instance avec plusieurs types (dont ICollection) afin de déterminer si un de ces types peut éviter l’énumération. Cette méthode retourne un boolean, dont la valeur sera vrai si cette méthode a permis d’éviter l’énumération.
var enumarable = Enumerable.Range(1, 100);
if (enumarable.TryGetNonEnumeratedCount(out var count))
{
Console.WriteLine($"Count optimized result : {count}");
}
else
{
Console.WriteLine($"Count get by enumerating each item : {enumarable.Count()}");
}
Enumerable.Chunk
Cette méthode vous permet de découper une instance de type Enumerable en plusieurs instances de tailles spécifiées. La dernière instance peut contenir moins d’éléments. Par exemple dans le cas où vous demandez de diviser une liste de 25 éléments en liste de 10 éléments, vous obtiendrez deux listes de 10 éléments et une liste de 5 éléments.
var enumarable = Enumerable.Range(1, 25);
var enumerables = enumarable.Chunk(10);
foreach(var item in enumerables)
{
Console.WriteLine($"Min : {item.Min()} - Max : {item.Max()}");
}
// Will output
// Min : 1 - Max : 10
// Min : 11 - Max : 20
// Min : 21 - Max : 25
Enumerable.MinBy et MaxBy
MinBy() et MaxBy() vous permettent de retourner un élément de la liste, sur base du minimum ou du maximum sur une propriété spécifique.
var developers = GetDevelopers();
var minDeveloper = developers.MinBy(dev => dev.Name);
var maxDeveloper = developers.MaxBy(dev => dev.Name);
Console.WriteLine($"{minDeveloper!.Name} loves {minDeveloper.FavoriteLanguage}!"); // Output Christophe loves Blazor!
Console.WriteLine($"{maxDeveloper!.Name} loves {maxDeveloper.FavoriteLanguage}!"); // Output Elliot loves Java!
IEnumerable<Developer> GetDevelopers()
{
yield return new Developer("Damien", "C#");
yield return new Developer("Christophe", "Blazor");
yield return new Developer("Elliot", "Java");
}
record Developer(string Name, string FavoriteLanguage);
Dans le même principe, vous avez également accès aux nouvelles méthodes suivantes : DistinctBy(), ExceptBy(), IntersectBy() et UnionBy().
Enumerable.ElementAt
La méthode ElementAt() existait déjà avant le .Net 6. A présent, vous pouvez trouver un élément en démarrer de la fin de votre Enumerable. Attention, si vous partez de la fin, l’index démarre à 1 et non 0. ^0 vous retournera donc une exception.
var developers = GetDevelopers();
var firstDeveloper = developers.ElementAt(0);
var lastDeveloper = developers.ElementAt(^1);
Console.WriteLine($"{firstDeveloper!.Name} loves {firstDeveloper.FavoriteLanguage}!"); // Output Damien loves C#!
Console.WriteLine($"{lastDeveloper!.Name} loves {lastDeveloper.FavoriteLanguage}!"); // Output Elliot loves Java!
IEnumerable<Developer> GetDevelopers()
{
yield return new Developer("Damien", "C#");
yield return new Developer("Christophe", "Blazor");
yield return new Developer("Elliot", "Java");
}
record Developer(string Name, string FavoriteLanguage);
Enumerable.FirstOrDefault()
Comme pour ElementAt(), la méthode FirstOrDefault() existait avant .Net6. A présent, vous pourrez passer en paramètre, la valeur par défaut si votre instance de Enumerable ne contient aucun élément.
var developers = Enumerable.Empty<Developer>();
var firstDeveloper = developers.FirstOrDefault(new Developer("Damien", "C#"));
Console.WriteLine($"{firstDeveloper!.Name} loves {firstDeveloper.FavoriteLanguage}!"); // Output Damien loves C#!
// Equivalent before .NET 6 :
var oldDeveloper = developers.DefaultIfEmpty(new Developer("Damien", "C#")).FirstOrDefault();
record Developer(string Name, string FavoriteLanguage);
Il est également possible de passer la valeur par défaut pour les méthodes LastOrDefault() et SingleOrDefault().
Enumerable.Take()
Si vous désirez prendre le troisième et quatrième éléments de votre liste d’éléments, avant .Net 6, vous pouviez le faire de cette manière : Take(4).Skip(2). En .NET 6, il existe une manière simplifiée de le faire.
var developers = GetDevelopers();
foreach(var developer in developers.Take(2..4))
{
Console.WriteLine($"{developer!.Name} loves {developer.FavoriteLanguage}!");
}
IEnumerable<Developer> GetDevelopers()
{
yield return new Developer("Damien", "C#");
yield return new Developer("Christophe", "Blazor");
yield return new Developer("Elliot", "Java");
yield return new Developer("Jules", "Python");
yield return new Developer("Mark", "Python");
}
record Developer(string Name, string FavoriteLanguage);
Enumerable.Zip()
La méthode Zip(), déjà disponible avant la sortie de .Net 6, permet de créer des tuples en fusionnant deux listes.
string[] fruits = { "Lemon", "Orange", "Coca" };
string[] colors = { "Yellown", "Orange", "Black" };
foreach((string fruit, string color) in fruits.Zip(colors))
{
Console.WriteLine($"{fruit} - {color}");
}
En .Net 6, vous pouvez maintenant fusionner 3 listes.
string[] fruits = { "Lemon", "Orange", "Coca" };
string[] colors = { "Yellown", "Orange", "Black" };
string[] state = { "Solid", "Solid", "Liquid" };
foreach ((string fruit, string color, string theState) in fruits.Zip(colors, state))
{
Console.WriteLine($"{fruit} - {color} - {theState}");
}
Enumerable.Min() et Enumerable.Max()
Dernière nouveauté, vous pouvez spécifier l’implémentation de IComparer à utiliser pour définir l’élément min ou max de votre liste.
var developers = GetDevelopers();
var maxDeveloper = developers.Max(new DeveloperComparer());
Console.WriteLine($"{maxDeveloper!.Name} love {maxDeveloper.FavoriteLanguage}");
IEnumerable<Developer> GetDevelopers()
{
yield return new Developer("Damien", "C#");
yield return new Developer("Christophe", "Blazor");
yield return new Developer("Elliot", "Java");
yield return new Developer("Jules", "Python");
yield return new Developer("Mark", "Python");
}
public record Developer(string Name, string FavoriteLanguage);
public class DeveloperComparer : IComparer<Developer>
{
public int Compare(Developer? x, Developer? y)
{
return string.Compare(x?.Name, y?.Name, StringComparison.OrdinalIgnoreCase);
}
}
Conclusion
Vous connaissez à présent toutes les nouveautés LINQ en .Net 6. Vous pouvez également connaitre toutes les nouveautés sur C#10 ici. N’hésitez pas à donner votre avis en commentaire sur ces nouvelles fonctionnalités, et surtout de partager cet article si vous avez aimé celui-ci 🙂