Accueil > Les nouveautés .NET 9 et C# 13 avec des exemples
Abdelkrim Bourennane
10 décembre 2024

Les nouveautés .NET 9 et C# 13 avec des exemples

Les Nouveautés .NET 9 et C# 13 Avec des Exemples

La conférence .NET 2024 s’est tenue il y a quelques jours, présentant les dernières versions de .NET et de C#. Voici un tour d’horizon des nouveautés les plus intéressantes, accompagnées d’exemples pratiques pour les développeurs.

Nouveautés dans C# 13

C# 13 introduit plusieurs améliorations pratiques.

Amélioration du mot-clé params

La première amélioration concerne le mot-clé params.

Auparavant, il n’était pas possible d’utiliser le mot-clé params avec des types de collections autres que des tableaux :

Dans la nouvelle version, il est maintenant possible d’utiliser n’importe quel type de collection, ainsi que System.Span<T> et System.ReadOnlySpan<T> :

Cette fonctionnalité permet aux développeurs de librairies de mieux concevoir leurs API et, dans certains cas (par exemple avec ReadOnlySpan<T>), d’éviter des allocations de tableaux supplémentaires.

Le Type Lock

Cette version de C# introduit un nouveau mécanisme de verrouillage avec un nouveau type, Lock, dans le namespace System.Threading.

Ce type sert d’alternative améliorée à l’ancienne manière de verrouiller, qui est basée sur l’API Monitor.

L’exemple ci-dessous montre comment le verrouillage était effectué avant C# 13 :

Remarquez que l’objet _lock peut être de n’importe quel type (ici c’est object, mais cela peut être n’importe quel type de référence). Cela peut provoquer des ambiguïtés, en particulier si son nom est autre que _lock.

De plus, cette utilisation du mot-clé lock utilise l’API Monitor en interne.

Avec le nouveau type Lock, le code ci-dessus ressemblera à ceci :

Le type Lock communique explicitement son intention, ce qui est important pour la lisibilité du code.

De plus, lorsque le mot-clé lock est utilisé avec un objet de type Lock, il utilise une nouvelle API légèrement plus performante que l’ancienne API Monitor.

Un simple benchmark des deux implémentations montre que le nouveau Lock est légèrement plus rapide et provoque moins de contentions de verrouillage :

Nouveau Lock - Nouveautés dans C#13
Lock – Nouveautés dans C#13

Initialisation d’un tableau à partir de la fin dans l’initialisation d’objet

Dans C# 12, si une classe avait une propriété de type tableau :

Il n’était pas possible d’initialiser le tableau en utilisant la syntaxe d’indice “à partir de la fin” :

Cela aurait généré une erreur :

Argument type ‘System.Index’ is not assignable to parameter type ‘int’

Avec C# 13, cette syntaxe fonctionne désormais comme prévu.

Propriétés partielles et indexeurs partiels

Avant C# 13, seules les méthodes dans une classe partielle pouvaient être marquées comme partial. Avec C# 13, les propriétés et les indexeurs peuvent également être partiels. Voici un exemple :

Priorisation des surcharges

Lorsque plusieurs surcharges de la même méthode existent, C# 13 permet aux développeurs de donner un indice au compilateur sur la surcharge à privilégier grâce au nouvel attribut OverloadResolutionPriorityAttribute :

Lors de l’utilisation de la méthode ci-dessus, le compilateur privilégie la surcharge qui prend un Span quand c’est possible et dépriorise la surcharge avec params.

L’ordre de priorité, du plus élevé au plus bas (les nombres plus élevés signifiant une priorité plus haute), est le suivant :

Cette fonctionnalité est particulièrement utile pour les auteurs de librairies qui souhaitent privilégier des surcharges plus récentes et efficaces par rapport à des anciennes surcharges.

Mises à jour dans le Runtime et les bibliothèques de .NET 9

Avec les nouvelles fonctionnalités du langage, .NET 9 introduit des améliorations et de nouvelles APIs dans la Librairie de Base (BCL) et le runtime.

GUID monotoniques

Avant .NET 9, les GUIDs créés avec la méthode Guid.NewGuid() étaient des UUID de version 4, qui, selon la RFC 9562, sont générés de manière aléatoire ou pseudo-aléatoire.

Bien que ces identifiants soient efficaces pour éviter les collisions, ils ne conviennent pas comme champs indexés dans une base de données en raison de problèmes de localité d’index, notamment lorsqu’ils sont utilisés comme clés primaires.

Jusqu’à présent, les développeurs devaient utiliser des bibliothèques tierces comme NuGet Gallery | Ulid 1.3.4 ou NewId de MassTransit.

.NET 9 introduit des UUID de version 7, qui sont des identifiants ordonnés par le temps. Pour en créer un, utilisez la nouvelle méthode de fabrique :

En interne, cette méthode utilise l’heure UTC pour la génération, mais vous pouvez fournir un DateTimeOffset pour une personnalisation :

Cette fonctionnalité est particulièrement utile pour créer des tests prévisibles et déterministes.

Encodage Base64 adapté aux URLs

Auparavant, les chaînes encodées en Base64 incluaient souvent des caractères ayant des significations spéciales dans les URLs, comme / et +. Par conséquent, les développeurs devaient encoder les chaînes Base64 pour les utiliser dans les URLs.

Dans .NET 9, vous pouvez maintenant encoder des chaînes en utilisant un alphabet Base64 adapté pour les URLs et les noms de fichiers, appelé Base64Url. Cela suit la norme décrite dans RFC 4648.

L’encodage Base64Url est disponible dans le namespace System.Buffers.Text

Nouvelles méthodes LINQ

LINQ introduit deux nouvelles méthodes qui simplifient la logique de regroupement et réduisent les allocations supplémentaires.

Méthode CountBy

Avant .NET 9, le comptage d’objets partageant la même propriété nécessitait un regroupement suivi d’une transformation :

Avec .NET 9, cela peut être fait de manière plus concise et plus performante:

Méthode AggregateBy

Toujours avec l’exemple précédent, pour avoir la somme des âges par propriété, il fallait précédemment écrire:

Désormais, vous pouvez écrire :

Ces nouvelles méthodes améliorent la lisibilité et minimisent les allocations intermédiaires.

Améliorations pour le traitement des tâches asynchrones

Auparavant, traiter plusieurs tâches en parallèle nécessitait une boucle avec Task.WhenAny :

.NET 9 introduit Task.WhenEach , en l’utilisant avec une boucle await foreach , ce qui donne un code plus clair :

Nouvelles collections

Deux nouvelles collections ont été ajoutées :

  • OrderedDictionary<TKey, TValue> : Un équivalent générique de l’ancien OrderedDictionary. Ce dictionnaire permet un accès indexé aux paires clé-valeur avec des méthodes comme Insert, RemoveAt et ElementAt.
  • ReadOnlySet<T> : Un wrapper pour les collections ISet<T>, offrant une vue en lecture seule. Il est analogue à ReadOnlyCollection<T> et ReadOnlyDictionary<TKey, TValue>, mais pour les ensembles.

Changements majeurs cassant (Breaking Changes)

Avec les nouvelles fonctionnalités et améliorations, certains changements majeurs impactent des fonctionnalités spécifiques. Ces changements sont classés en trois types :

  • Incompatibilités binaires : peuvent provoquer des erreurs lors de l’exécution.
  • Incompatibilités de source : peuvent provoquer des erreurs à la compilation.
  • Changements comportementaux : ne provoquent pas forcément d’erreurs mais peuvent modifier le comportement du code, pouvant entraîner des erreurs logiques.

Préférence pour les surcharges Span avec des expressions de collections vides

En C# 12, le compilateur préférait une surcharge prenant un Span<T> ou un ReadOnlySpan<T> comparé à d’autres surcharges lors de l’utilisation d’une expression de collection vide [], lorsque le type des éléments était ambigu. Par exemple, ce code utilisait Sum(ReadOnlySpan<int>) :

En C# 13, ce code résulte en une erreur de compilation (il est incompatible avec C# 12 au niveau du source) et produit l’erreur suivante :

Cela résulte d’une résolution des ambiguïtés dans l’interprétation des expressions de collections vides.

Pour corriger cette erreur, vous pouvez soit spécifier le type explicitement, soit utiliser l’attribut OverloadResolutionPriorityAttribute sur la méthode préférée.

Choix du type naturel pour les groupes de méthodes

En C# 12, référencer une méthode via son nom de groupe pouvait conduire à un comportement inattendu. Par exemple :

Dans l’exemple ci-dessus, x1 sélectionne Test1(this Program p, long[] a), et x2 sélectionne Test2(this object p, params long[] a), selon l’ordre de définition dans la classe E. Ce comportement inattendu en C# 12 était un effet secondaire non intentionnel d’une autre fonctionnalité.

En C# 13, cela résulte maintenant en une erreur de compilation.

Suppression des méthodes String.Trim*(params ReadOnlySpan<char>)

Les méthodes String.Trim, String.TrimLeft et String.TrimRight acceptant params ReadOnlySpan<char> ont été supprimées dans .NET 9.

Réduction de la longueur maximale de BigInteger

Dans .NET 9, la longueur maximale du type BigInteger est maintenant limitée à (2^31) – 1, ce qui correspond à environ 646,5 millions de chiffres.

Auparavant, BigInteger était limité à Array.MaxLength * 32, ce qui était pratiquement impossible à atteindre mais pouvait causer des OutOfMemoryException.

Modification du comportement de dotnet restore

La commande dotnet restore effectue maintenant un audit des packages transitifs pour détecter les vulnérabilités de sécurité. Si des vulnérabilités sont détectées, le SDK émet des warnings. Si votre projet traite les avertissements comme des erreurs, le SDK arrête le processus de restauration et émet une erreur au lieu d’un warning.

Les packages transitifs sont ceux utilisés par les packages que vous référencez directement.

Renforcement du type dans EnumConverter

Dans .NET 9, EnumConverter lève une exception lors de l’exécution si le type cible pour la conversion n’est pas un type énumération. C’est un changement comportemental.

Autres changements cassants et spécifiques aux technologies

En plus des changements majeurs dans le compilateur C#, le runtime .NET et la BCL mentionnés dans cet article, d’autres modifications existent, certaines étant spécifiques à certaines technologies. Pour tous les détails, veuillez consulter la page officielle : Breaking Changes in .NET 9 | Microsoft Learn.

Pour conclure

.NET 9 et C# 13 introduisent de nombreuses améliorations pratiques qui optimisent l’efficacité mémoire, les performances, la lisibilité du code et la productivité des développeurs.

Ces mises à jour répondent à divers besoins dans l’écosystème .NET, en bénéficiant aux développeurs d’applications, aux auteurs de bibliothèques et aux utilisateurs finaux.

Cet article a mis en avant les fonctionnalités que nous trouvons particulièrement utiles pour le développement quotidien, mais il ne couvre pas toutes les améliorations de cette version. Pour une liste complète, visitez What’s new in .NET 9 | Microsoft Learn.

Pour rester informé(e) sur les futures versions de .NET et C#, consultez les dépôts GitHub pour C# Language et .NET Runtime.

Nos autres articles
Commentaires
Laisser un commentaire

Restez au courant des dernières actualités !
Le meilleur de l’actualité sur le Cloud, le DevOps, l’IT directement dans votre boîte mail.