C# 9.0 : de nombreuses nouveautés, souvent inspirées de la programmation fonctionnelle
De F# à C#
Notre dossier sur la Build 2020 de Microsoft :
Le 03 juin 2020 à 06h30
6 min
Logiciel
Logiciel
Avant de plonger dans les nouveautés annoncées récemment par Microsoft pour Azure, voici un détour par C#, dont la version 9.0 a été lancée durant la conférence Build. Les nouveautés sont nombreuses, aussi bien pour la pratique usuelle que dans des cas beaucoup plus spécifiques.
Le C# reste aujourd'hui le langage fétiche de Microsoft. Il s'agit pour rappel d'un dérivé du C++, mais de plus haut niveau, puisqu'il reprenait initialement nombre de concepts de Java.
L'éditeur en assure toujours autant la promotion, puisqu'il peut servir aussi bien au développement d'applications natives et .NET que de pages web via ASP.NET. Aussi l'arrivée d'une nouvelle version majeure est-elle toujours un évènement, surtout dans le contexte d'une conférence dédiée aux développeurs.
Comme les connaisseurs pourront s'en apercevoir, beaucoup des apports de C# 9, qui arrive un peu plus d'un an après la version 8, ont trait à la programmation fonctionnelle et sont en fait directement inspirés de F#. Au point que l'on peut se demander aujourd'hui si ce dernier ne sert tout simplement pas de laboratoire d'essai à C#.
- WSL 2 gèrera les GPU et les interfaces Linux, Terminal 1.0, WinGet en preview
- Reunion d'UWP et Win32, Visual Studio, Live Share et Codespaces
- Au sein de Microsoft 365, Teams reste la star
- C# 9.0 : de nombreuses nouveautés, souvent inspirées de la programmation fonctionnelle
- Du machine learning « responsable » aux nouveautés Azure
Place aux propriétés Init-only
On commence avec les propriétés Init-only, qui viennent remédier à certaines limitations des initialiseurs d’objets. Ces derniers offrent en théorie un format flexible, étant particulièrement adaptés à la création imbriquée, pour une arborescence générée d'une traite par exemple. Mais ses propriétés se doivent d'être modifiables.
Les propriétés Init-only corrigent cette situation, les développeurs pouvant désormais se servir d’accesseurs init
, variantes des accesseurs set
:
public class Personne
{
public string Prénom { get; init; }
public string Nom { get; init; }
}
Dans l’exemple donné par Microsoft, toute affectation ultérieure aux propriétés Prénom
et Nom
renverra une erreur. Ces accesseurs init
ne pouvant être appelés que durant l’initialisation, ils peuvent muter les champs readonly
de la classe englobante, comme un développeur le pourrait avec un constructeur.
Cette particularité est utile pour rendre des propriétés individuelles immuables. Dans le cas cependant où il faudrait rendre immuable tout l’objet, on peut utiliser les Records. Dans l’exemple précédent, passer de « public class Person
» à « public data class Personne
» marque la classe comme Record, lui conférant des comportements de type value
.
Ces Records sont davantage définis par leur contenu que par leur identité. Et puisque leur contenu est prévu pour être immuable, les changements dans le temps doivent être représentés par de nouveaux Records. Ils représentent en fait l’état d’un objet à un instant donné.
Les expressions with
Une manière de développer différente, conçue pour des besoins spécifiques, et accompagnée d’un nouveau type d’expressions nommé with
. Elles utilisent la syntaxe des initialiseurs d’objets pour marquer la différence d'un nouvel objet pa rapport à un existant. Par exemple, si l’on souhaite créer une nouvelle entrée autrePersonne
en récupérant les propriétés de Personne
mais en en changeant simplement Nom
, on obtient :
var autrePersonne = personne with { Nom ="Dupont" };
En arrière-plan, un constructeur de copie labellisé protected
s’occupe de gérer l’opération.
Nouveaux patterns et opérateurs
Plusieurs types de nouveaux patterns font leur apparition dans C# 9.0.
public static decimal CalculateToll(object vehicle)=>
vehicle switch
{
...
DeliveryTruck t when t.GrossWeightClass > 5000 => 10.00 m + 5.00 m,
DeliveryTruck _=> 10.00 m,
_=> throw new ArgumentException("Not a known vehicle type", nameof(vehicle))
};
L’exemple fourni montre la manière dont le code devait être écrit jusqu’à présent pour le pattern matching. Dans C# 9.0, plusieurs éléments peuvent être notablement simplifiés. Par exemple, plus besoin de déclarer un identifiant de pattern, même un _
. Le développeur peut ainsi écrire directement le type : DeliveryTruck => 10.00 m,
Du changement également pour les opérateurs relationnels de type <
ou <=
. La partie DeliveryTruck
peut alors s’écrire comme une expression switch imbriquée, > 5000
et < 3000
étant des patterns relationnels :
DeliveryTruck t when t.GrossWeightClass switch
{
> 5000 => 10.00 m + 5.00 m,
10.00 m - 2.00 m,
_=> 10.00 m,
},
Des opérateurs logiques and
, or
et not
apparaissent dans la foulée. On peut par exemple écrire >= 3000 and 10.00 m,
pour représenter un intervalle. L’opérateur not
parle de lui-même et peut s’appliquer à de multiples situations. Par exemple pour définir des cas, en accompagnement de null
.
Autre cas classique, dans l’utilisation d’expressions if
, pour spécifier une action si une variable n’a pas la valeur spécifiquement définie, sans requérir de double parenthèses : if (e is not Customer) { ... }
Target typing, retours covariants et autres améliorations
C# 9.0 améliore le target typing, qui survient lorsqu’une expression obtient un type depuis le contexte de son utilisation. La nouvelle version allonge la liste des expressions prises en charge. Dans new
par exemple, plus besoin de spécifier le type dans la plupart des cas, comme dans Point p = new (3, 5);
On note d’autres nouveautés, comme les retours covariants, s’adressant à des cas particuliers, pour signaler qu’un forçage (override) de méthode dans une classe dérivée a un type de retour plus spécifique que la déclaration dans le type de base. Signalons aussi les fonctions lambdas statiques. La déclaration peut ainsi être accompagnée d’un mot servant de préfixe, la fonction lambda se comportant alors comme une méthode statique. Cela évite notamment la capture de paramètres.
Dans la liste des simplifications, on note celle du code de base d'une application passant de :
using System;
class Program
{
static void Main()
{
Console.WriteLine("Hello World!");
}
}
À une solution plus légère, où il est possible de se contenter de débuter le code directement après les using
, mais avant toute déclaration d'un espace de nom, précise Microsoft :
using System;
Console.WriteLine("Hello World!");
N'importe quelle fonctionnalité est disponible, des retours de code de statut à await
en passant par les arguments (args
), tant que tout est contenu dans un seul et même fichier. De quoi éviter des déclarations comme celles d'une méthode principale et d'une classe, inutiles pour une application très basique.
On pourrait également citer une simplification de la validation null
standard par l’ajout d’une petite annotation, les initialiseurs de modules, la reconnaissance de la méthode GetEnumerator
dans les boucles foreach
ou encore l’extension des méthodes Partial
, en supprimant notamment toutes les restrictions autour de leur signature.
Les développeurs intéressés pourront se rendre par ici où les changements sont détaillés. Mais aussi lire la liste complète des nouveautés depuis la page de statut du langage sur le dépôt GitHub associé. Une vidéo a également été mise en ligne à l'occasion de l'édition numérique de la Build 2020 :
C# 9.0 : de nombreuses nouveautés, souvent inspirées de la programmation fonctionnelle
-
Place aux propriétés Init-only
-
Les expressions with
-
Nouveaux patterns et opérateurs
-
Target typing, retours covariants et autres améliorations
Commentaires (34)
Vous devez être abonné pour pouvoir commenter.
Déjà abonné ? Se connecter
Abonnez-vousLe 03/06/2020 à 08h00
Le 03/06/2020 à 08h03
Le 03/06/2020 à 08h16
Ben, moi ce que j’aime avec ces langages multi-paradigmes, c’est que tu peux justement à la fois être verbeux sur la partie structurante (ex la partie web) mais aussi profiter de la syntaxe fonctionnelle pour exprimer ton métier de manière plus concise (et donc plus lisible).
J’ai de petits projets sans prétention en C# + F# pour apprendre un peu le fonctionnel, et c’est assez cool de pouvoir écrire la partie web et technique en impératif tout en exprimant totalement ton métier en F#, qui a pour lui une syntaxe de création de type extrêmement courte, qui t’encourage à créer un nouveau type pour quasiment chaque utilisation.
Si tu veux un exemple sympa, tu as ici un seul fichier F# qui définit toutes les règles métier d’un jeu d’échec : GitHubet, si je peux confirmer que quand tu débutes c’est assez difficile à écrire (syntaxe + modèle mental à changer totalement) je trouve assez fascinant à quel point, même en ayant jamais fait de programmation fonctionnelle, ni jamais lu la moindre ligne de F#, c’est extrêmement expressif et facile à lire. Tu peux quasiment faire lire ce bout de code a responsable produit ou au client pour qu’il valide que c’est bien ce qu’il veut.
Et le truc le plus merveilleux, c’est que tu peux ajouter le .fsproj contenant ce code dans un .sln et appeler ces fonctions comme si elles étaient de bêtes méthodes statiques.
Le 03/06/2020 à 09h26
J’ai un sentiment similaire.
Je ne connais pas le langage, mais les nouveautés présentées ici je les trouve assez intéressantes, des manières plutôt élégantes de retranscrire certaines logiques, et à priori pas compliquées à comprendre.
C’est juste que ça rend le code moins facilement transportable vers un autre langage, mais bon dans la pratique il me semble que quoiqu’il arrive passer un programme d’un langage à l’autre revient toujours à tout réécrire et repenser donc… " />
Je suis particulièrement fan du “with” (évite de devoir se palucher à la main un “copieur” pour les cas d’usage basiques) et le “switch multi-conditionnel”.
Je ne sais pas si ces “techniques” sont courantes dans d’autres langages, mais ça a l’air bien bien efficace pour gagner du temps.
Le 03/06/2020 à 09h57
Je suis pas hyper-fan de certaines des fonctionnalités qui ont été présentés.
Alors oui, autant le With peut être sympa mais pour les and, or et not …
En fait, je pense avoir été traumatisé avec le VB6 et le VB.Net, c’est quand que MS les euthanasies ? " />
Le 03/06/2020 à 10h07
Et on prononce C sharp ou C dièse ? " />
Le 03/06/2020 à 10h42
C hashtag " />
Bon. C sharp en vrai.
Le 03/06/2020 à 10h51
J’ai découvert dotnet et C# en 2001 et au début je disais C dièse," />" /> J’étais au collège la bonne époque quoi.
Le 03/06/2020 à 15h50
Tu devrais te mettre au Go alors si ce n’est pas déjà le cas, tu pourras t’y faire plein de copains! C’est plein de vieux bougons qui veulent pas de fonctionnel " />
(moi j’y suis mais contre mon gré)
Le 03/06/2020 à 15h53
Tout d’abord, merci pour le lien. Connaissant les règles métier, ça va m’être utile pour continuer ma découverte de F#.
En fait F#, je n’ai jamais eu l’occas de l’utiliser en prod. J’ai juste fait quelques tests découverte, pour le plaisir, quand j’ai vue qu’on pouvait “mixer”.
Intuitivement, j’aurais plutôt tendance à préférer que chaque syntaxe “reste chez elle”. Les .cs avec la syntaxe C# “tradi, les .fs avec la syntaxe F#.
Après, j’avoue, j’aime bien quand c’est verbeux (et en plus, je suis pour commenter le code, surtout les règles métiers). Par exemple, je n’aime pas quand les requêtes Linq sont d’un seul tenant et trop complexe. Si on peut faire tout aussi efficace en découpant un peut son code, ça me va mieux (enfin, je ne veux pas non plus empiler les For each " />).
Mais bon, je comprends que ça plaise et puis y a des nouveautés bien sympa j’avoue. Rien qu’Init, with et les changements sur partial me suffisent pour déjà aimer cette v9 " />
Le 03/06/2020 à 16h05
Le 03/06/2020 à 18h07
Le 03/06/2020 à 18h14
Le 03/06/2020 à 19h02
Le 03/06/2020 à 19h38
Hmmmm. Plus un truc évolue plus c’est dans les détails et on est pas sur que ce sera très utilisé.
On en a vu plus d’un utiliser des “truc précis” pour écrire dans son rapport de stage. Et ensuite une fois le stagiaire parti… de réécrire en mode “tout le monde comprends et comprendra à la relecture dans 2 ans et demi”.
J’ai rien contre ces nouveautés mais il faut toujours se poser la question dans le monde de l’entreprise :
Est-ce qu’on en a besoin ?
Si oui est-ce la majeure partie du projet ?
…
Le 03/06/2020 à 20h22
De mon point de vue, init et with peuvent justement rentré dans les changements utiles et rentables en projet. Ce sont des notions très faciles à acquérir, et ça clarifié l’intention du code. Ce n’est que mon avis.
Pour le stagiaire, je comprend pas trop, pas de tuteur pour relire son code ou vpus lui lâchez la bride pour qu’il puisse faire ce qu’il veut, dans l’objectif de l’intégrer à son rapport de stage ?
Le 04/06/2020 à 06h25
Le 04/06/2020 à 06h46
Le 04/06/2020 à 06h58
Le 04/06/2020 à 07h04
Le 04/06/2020 à 09h31
” Ce sont des notions très faciles à acquérir, et ça clarifie l’intention du code”
Je trouve ta formulation très pertinente. " />
Le 04/06/2020 à 09h35
Eh oui, peu importe la qualité des outils si on ne sait pas s’en servir correctement… " />
Un peu lointain comme parallèle mais j’ai quand même envie (Big up à celui qui trouvera d’où vient la citation -pas exactement ces termes, mais asez proche, j’ai pas le tome sous la main. Indices : manga, Japon “renaissance”, samuraï). :)
“Lorsque tu fais face à un advesaire, tu ne te préoccupes pas de son arme. Tu cherches à savoir s’il a la force nécessaire pour t’écraser.”
Le 04/06/2020 à 09h49
Le 04/06/2020 à 11h38
À chaque fois que je vois un article qui parle de fa dièse, je ne peux m’empêcher de penser : tiens, ils ont fait une version .NET de Fortran ? " />
Le 04/06/2020 à 12h04
Le 09/06/2020 à 11h30
Bah oui je vois pas où est le problème ?
C’est comme les classes au final c’est vachement compliqué pour rien la portée des attributs et des méthodes.
Tous les attributs en public, toutes les méthodes en statiques, et voilàààààà ! \o/
Si quelqu’un fait ça pour de bon, vous n’êtes pas obligé de le payer. En revanche éventuellement le (lui) faire payer me semble obligatoire… " />
Le 09/06/2020 à 14h19
Surtout quand le code concerné est en VB6 et que l’IDE est … " />
Le 03/06/2020 à 06h44
A noter que pour profiter pleinement des dernières nouveautés du langage (C# 8 et ultérieur !), il ne faut pas utiliser .NET Framework, mais .NET Core (ou plus précisément, un framework compatible .NET Standard 2.1 et ultérieur).
.NET Framework ne sera pas pleinement compatible, car certaines fonctionnalités nécessite des modifications au niveau du CLR (Common Language Runtime), qui, dans ce cas précis, ne sera pas mis à jour pour des raisons de pérennité.
Le 03/06/2020 à 07h05
Pourquoi avoir mis ça dans le même dossier que les articles concernant la Build 2020 de windows ?
Bon sinon moi, je n’aime pas cette évolution vers le fonctionnel. Je dois être passé du côté des vieux bougons " />
Le 03/06/2020 à 07h26
Il y a quelques truc très intéressants comme le not et la version Crosoft du Final, mais le reste aussi simplifiant soit il ne fait que rendre le code encore plus illisible " />
Je continuerais comme dab avec mes étudiants en leurs montrant comment être verbeux, car il est toujours plus facile de passer de verbeux à crado que l’inverse…
Le 03/06/2020 à 07h41
C’est pas dégueu comme évolutions. C# et .NET ne m’a jamais vraiment attiré mais j’avoue que depuis .NET Core et C# 8 et 9 maintenant, on sent que Microsoft n’a pas du tout l’intention de laisser stagner son (pourtant vieux) bébé.
Je trouve assez chelou d’utiliser le mot clé switch pour le pattern matching avec une syntaxe totalement différence du switch classique là où la plupart des langages proposent soit switch et match, soit uniquement match. Mais bon c’est du pinaillage.
Le 03/06/2020 à 07h48
Le 03/06/2020 à 07h52
Le 03/06/2020 à 07h58