Developpez.com - Programmation

Le Club des Développeurs et IT Pro

C# 9.0 est en développement et Microsoft prévoit de nouvelles fonctionnalités comme les constructeurs principaux

Qui permettent de réduire les frais généraux de programmation

Le 2020-03-19 14:09:38, par Bill Fassinou, Chroniqueur Actualités
Microsoft a publié C# 8.0 en septembre dernier et a aussi entamé les travaux pour la version 9.0 du langage. Plusieurs propositions ont été faites parmi lesquelles l’on retrouve des fonctionnalités très intéressantes. La prochaine version de C# pourrait apporter les expressions switchs, les types records et un code de validation des paramètres nuls simplifié. Le jalon C# 9.0 sur GitHub recense toutes les fonctionnalités proposées par la communauté, mais n’annonce aucune date de sortie officielle pour la prochaine version de C#. Voici quelques-unes des propositions.

Validation nulle simplifiée

Cette nouvelle fonctionnalité permet de simplifier la validation des paramètres standard en utilisant une petite annotation sur les paramètres. En décorant la valeur d'un paramètre à une méthode avec une petite annotation, cela facilite la logique interne et l’on n’a plus besoin de clauses de validation/garde nulles. Cela a pour effet de réduire le code de validation passe-partout.

Constructeurs principaux

Selon la description de la fonctionnalité, les constructeurs principaux permettent de réduire les frais généraux de programmation en plaçant les arguments des constructeurs directement dans le champ d'application d'une classe. En gardant votre logique de construction minimale, vous éliminez le code superflu qui encourage l'écrémage des fichiers de code au lieu de faire un véritable examen du code. En ayant moins de code, vous rendez plus difficile la dissimulation de bogues et votre code est plus significatif.

En d’autres mots, vous n’avez plus besoin de déclarer explicitement un champ d'appui. Cela simplifie tous ces constructeurs, ces champs, ces getters/setters de propriété, etc. auxquels vous êtes si habitués.


Classes record

C’est un formulaire de déclaration simplifié pour une classe C# ainsi que les types de structures. Les records sont similaires aux constructeurs principaux cités en haut. Le but de cette proposition est de supprimer la nécessité d'écrire autant de code passe-partout lors de la création d'une nouvelle classe ou d’une structure. Ils fournissent un mécanisme de déclaration d'un type de données en décrivant les membres de l'agrégat ainsi que le code supplémentaire ou les écarts par rapport à l'habituel passe-partout, le cas échéant.

Unions discriminées via les classes Enum

Le terme d'union discriminée (union disjointe) est emprunté aux mathématiques. L'union discriminée est également largement utilisée dans les langages de programmation, et sert à additionner les types de données existants. Dans C# 9.0, il permet de définir des types pouvant contenir un nombre quelconque de types de données différents. Leur fonctionnalité est comparable à celle des unions C++ ou des variantes Visual Basic, avec l'avantage d'être plus sûres.
Les unions discriminées sont utiles pour les données hétérogènes ; les données qui peuvent avoir des cas individuels, avec des cas de validité et d'erreur ; les données dont le type varie d'une instance à l'autre. En outre, elle offre une alternative pour les petites hiérarchies d'objets.

CallerArgumentExpression

Cette fonctionnalité a pour but de permettre aux développeurs de capturer l'expression transmise à une méthode, de permettre de meilleurs messages d'erreur dans les API de diagnostic/test et de réduire le nombre de frappes.

Déclarations de haut niveau et déclarations des membres, englobant un dialecte de scripts dans le C#

Le compilateur C# comprend actuellement un dialecte du langage utilisé pour les scripts et à des fins interactives. L'utilisation du dialecte de script a été relativement mineure, mais l'usage s'intensifie. Le plan est basé sur la conviction que des extensions de C# pourraient être ajoutées au langage plutôt que d'avoir un dialecte de script séparé.

Le C# est un langage de programmation orienté objet appartenant à la famille C, et similaire à Java. Il prend également en charge la collecte des déchets et la programmation orientée composants, en utilisant des paquets de fonctionnalités autonomes et autodescriptives. La liste de toutes les propositions pour C# 9 est disponible sur la page GitHub du langage.

Source : C#

Et vous ?

Qu'en pensez-vous ?

Voir aussi

.NET Core 3.0 est disponible avec le support du développement d'applications Windows Desktop C# 8.0, ARM64, une prise en charge JSON intégrée rapide et de nombreuses autres améliorations

C# 8.x va introduire la fonctionnalité Records pour faciliter la création des classes POCO, selon Developers Anonymous

Microsoft livre un aperçu des nouveautés de C# 8.0 et envisage de commencer à livrer cette version dans les préversions de Visual Studio 2019
  Discussion forum
11 commentaires
  • mermich
    Membre expérimenté
    Dans le debat classe vs struct, il ya aussi les generiques :

    Code :
    public void Prout<T>(T t) where T : class
    ce qui engrange des doublon si l'on doit a la fois gerer des classes et des structures...
    Au final avec le temps je pousse mes collegues a ne pas utiliser les struct pour toutes ces raisons. Mais il reste ce soucis de mutabilite que l'on ne desire pas forcement.

    Je me demande si ces data class fonctionnent correctement lors d'un post mvc, par exemple
  • mermich
    Membre expérimenté
    Ca me fait penser pas mal q certaines fonctionnalites des koltin, je dis n'importe quoi ou c'est bien le cas ?
  • codec_abc
    Membre confirmé
    Je connais pas Kotlin mais l'inspiration vient surement de F# qui à ce genre de features depuis longtemps. C'est la stratégie de Microsoft depuis longtemps. F# sert en quelque sorte de Labo et les features sont ensuite intégré dans C#.
  • StringBuilder
    Expert éminent
    Bonjour,

    Y'a un truc que j'ai pas bien compris avec le "record" (mot clé data).

    Du coup, c'est quoi la différence entre un "struct" et un "class data", mise à part que le "class data" est readonly ?

    Pourquoi ne pas avoir créé un "struct readonly" à la place du coup ?

    Transformer une déclaration de type référence en type valeur, alors qu'une déclaration de type valeur existe déjà, je suis perplexe !
  • StringBuilder
    Expert éminent
    Envoyé par zero_divide 
    Moi qui structure mon code selon le "Domain-driven design (DDD)", c’est évidemment pour représenter un Value Object.

    Justement, j'ai un peu du mal à comprendre…

    A la base, une instance d'objet, c'est une référence.
    Donc un objet valeur c'est à la base plus ou moins antonyme.

    C#, depuis la version 1.0 a coupé la poire en deux, en proposant les structures, qui n'ont rien à voir avec les structures qu'on peut trouver dans d'autres langages : ce sont des objets à part entière (ils héritent d'ailleurs du type objetc) et supportent méthodes et constructeurs... La seule grosse différence avec une classe, c'est d'être justement un type valeur.

    Code csharp :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    using System; 
      
    namespace StructOrObject 
    { 
        class Program 
        { 
            static void Main(string[] args) 
            { 
                MaStructure s1 = new MaStructure("Alfred", "E. Neuman"); 
                Console.WriteLine(s1.FullName); 
                Console.WriteLine(s1.NbNotEmptyChars()); 
      
                MaStructure s2 = new MaStructure() { FullName = "Alfred E. Neuman" }; 
                Console.WriteLine(s2.FullName); 
                Console.WriteLine(s2.NbNotEmptyChars()); 
      
                Console.WriteLine(s1.Equals(s2)); 
            } 
        } 
      
        struct MaStructure 
        { 
            public string FullName { get; set; } 
      
            public MaStructure(string firstName, string lastName) 
            { 
                FullName = $"{firstName} {lastName}"; 
            } 
      
            public int NbNotEmptyChars() 
            { 
                if (string.IsNullOrWhiteSpace(FullName)) 
                { 
                    return 0; 
                } 
                else 
                { 
                    return FullName.Replace(" ", "").Length; 
                } 
            } 
        } 
    }

    Du coup, un "Value Object", existe déjà dans .NET et s'appelle struct...

    Le seul truc qui manque, c'est qu'on ne peut pas initialiser une proriété readonly directement avec un new MaStructure() { FullName = "Toto" } mais je ne vois pas ce qui empêchait de mettre "init" sur les structures aussi...
    Dans quel cas un "class data" est-il différent d'un "struct" donc toutes les propriétés sont readonly ?

    Bref, je pige vraiment pas.
  • Programmator
    Membre régulier
    Envoyé par StringBuilder

    Le seul truc qui manque, c'est qu'on ne peut pas initialiser une proriété readonly directement avec un new MaStructure() { FullName = "Toto" } mais je ne vois pas ce qui empêchait de mettre "init" sur les structures aussi...
    Dans quel cas un "class data" est-il différent d'un "struct" donc toutes les propriétés sont readonly ?

    Bref, je pige vraiment pas.
    Les classes et les structures ont aussi 2 différences majeures :
    • Les instances de classes sont stockées dans le tas, qui est une zone mémoire large gérée par le ramasse-miettes. Alors que les instances de structures sont stockées sur la pile et détruites automatiquement lorsqu'on sort de la portée.
    • Les classes sont dérivables, alors que les structures ne le sont pas.


    Les classes data restent des classes et continuent donc de profiter de ces 2 caractéristiques propres aux classes.
    De plus, en lisant l'article original de Microsoft, je crois comprendre que les classes data ont besoin de l'héritage dans certains scénarios (cf. chapitre Value-based equality and inheritance)
  • StringBuilder
    Expert éminent
    En effet, bien vu pour l'héritage. J'avais pourtant l'exemple sous les yeux, je n'y avais pas pensé.

    Par contre, pour la partie gestion de la mémoire, j'ai envie de dire :
    - on s'en moque un peu (après tout, c'est la sauce interne du Framework, ça peut tout à fait changer d'une version à l'autre, voir même d'une implémentation à l'autre)
    - mais surtout, je ne vois pas l'intérêt de stocker des value objects dans une zone mémoire gérée par le GC. En effet, vu que ce sont des objets valeur, il ne peut y avoir qu'une seule référence (c'est con de manipuler une référence d'un type value... c'est un peu dommage d'utiliser un objet valeur pour n'en manipuler que la référence. Et très peu de chance/raison de recréer le même objet exactement, (et vérifier qu'il est identique à un détruit précédemment prendra de toute façon autant de temps que de le récupérer) sinon, pourquoi l'avoir détruit ?
  • François DORIN
    Expert éminent sénior
    Envoyé par StringBuilder
    Y'a un truc que j'ai pas bien compris avec le "record" (mot clé data).

    Du coup, c'est quoi la différence entre un "struct" et un "class data", mise à part que le "class data" est readonly ?
    A priori, un class data reste une classe. Donc passage par référence. Le passage en tant que paramètre dans une méthode ou la copie dans une variable serait donc bien rapide que dans le cas d'une struct, notamment lorsqu'il y a beaucoup d'attributs.

    L'objectif c'est de donner un comportement de type "valeur" à une classe. L'égalité, par exemple, se base non plus sur les références, mais bien sur la valeur des attributs sous-jacents.

    Envoyé par Programmator

    Les instances de classes sont stockées dans le tas, qui est une zone mémoire large gérée par le ramasse-miettes. Alors que les instances de structures sont stockées sur la pile et détruites automatiquement lorsqu'on sort de la portée.
    Partiellement inexacte. Les types valeur peuvent être allouées sur le tas et non sur la pile dans certaines condicitions. Par exemple, en cas de boxing :
    Code :
    1
    2
    object monEntier = 3; // alloué sur le tas !
  • Programmator
    Membre régulier
    Envoyé par François DORIN
    A priori, un class data reste une classe. Donc passage par référence. Le passage en tant que paramètre dans une méthode ou la copie dans une variable serait donc bien rapide que dans le cas d'une struct, notamment lorsqu'il y a beaucoup d'attributs.

    L'objectif c'est de donner un comportement de type "valeur" à une classe. L'égalité, par exemple, se base non plus sur les références, mais bien sur la valeur des attributs sous-jacents.

    Partiellement inexacte. Les types valeur peuvent être allouées sur le tas et non sur la pile dans certaines condicitions. Par exemple, en cas de boxing :
    Code :
    1
    2
    object monEntier = 3; // alloué sur le tas !
    Je partage tout à fait ce que tu dis François concernant le comportement de type valeur. C'est d'ailleurs déjà ce qui existe avec le type string, qui se comporte comme un type valeur bien que ce soit un type référence.

    Concernant l'allocation mémoire, même dans le boxing, la règle des types valeurs stockés sur la pile reste vraie. C'est un mécanisme que j'ai bien étudié pour faire mon cours C# et voici ce que j'ai compris :
    3 est un type valeur qui est donc stocké sur la pile.
    monEntier étant de type object, il doit obligatoirement référencer un emplacement du tas. S'il pointait sur un emplacement de la pile, cela créerait un défaut de sécurité potentiel. Par conséquent, le runtime réserve un bloc de mémoire sur le tas, y copie la valeur de l'entier 3, puis référence cette copie dans l’objet monEntier. Ceci est illustré par le schéma suivant :



    La règle types valeurs stockés sur la pile et types références stockés sur le tas est ainsi toujours respectée.
  • zero_divide
    Membre à l'essai
    Moi qui structure mon code selon le "Domain-driven design (DDD)", c’est évidemment pour représenter un Value Object.