Microsoft présente un aperçu de trois nouvelles fonctionnalités de C# 12, dont les constructeurs primaires pour les classes ou les structures et la définition d'alias pour tous les types

Nous sommes ravis de présenter en avant-première trois nouvelles fonctionnalités de C# 12 :
  • Constructeurs primaires pour les classes et les structures non enregistrées
  • Utilisation d'alias pour n'importe quel type
  • Valeurs par défaut pour les paramètres des expressions lambda

Pour tester vous-même ces fonctionnalités, vous pouvez télécharger la dernière version préliminaire de Visual Studio 17.6 ou la dernière version préliminaire de .NET 8.

Nom : csharp12.png
Affichages : 17782
Taille : 82,5 Ko

Constructeurs primaires pour les classes et les structures non enregistrées

Les constructeurs primaires vous permettent d'ajouter des paramètres à la déclaration de la classe elle-même et d'utiliser ces valeurs dans le corps de la classe. Par exemple, vous pouvez utiliser les paramètres pour initialiser les propriétés ou dans le code des méthodes et des accesseurs de propriété. Les constructeurs primaires ont été introduits pour les enregistrements en C# 9 dans le cadre de la syntaxe positionnelle des enregistrements. C# 12 les étend à toutes les classes et structures.

La syntaxe de base et l'utilisation d'un constructeur primaire sont les suivantes :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
public class Student(int id, string name, IEnumerable<decimal> grades)
 
{
 
    public Student(int id, string name) : this(id, name, Enumerable.Empty<decimal>()) { }
    public int Id => id;
    public string Name { get; set; } = name.Trim();
    public decimal GPA => grades.Any() ? grades.Average() : 4.0m;
}

Les paramètres du constructeur primaire de la classe Student ci-dessus sont disponibles dans tout le corps de la classe. L'une des façons de les utiliser est d'initialiser les propriétés. Contrairement aux enregistrements, les propriétés ne sont pas automatiquement créées pour les paramètres du constructeur primaire dans les classes et les structures sans enregistrement. Cela s'explique par le fait que les classes et les structures non enregistrées sont souvent plus complexes que les enregistrements, car elles combinent des données et un comportement. Par conséquent, elles ont souvent besoin de paramètres de construction qui ne doivent pas être exposés. La création explicite de propriétés permet de savoir quelles données sont exposées, ce qui est conforme à l'utilisation courante des classes. Les constructeurs primaires permettent d'éviter de déclarer des champs privés et de faire en sorte que des corps de constructeurs triviaux attribuent des valeurs de paramètres à ces champs.

Lorsque les paramètres du constructeur primaire sont utilisés dans des méthodes ou des accesseurs de propriété (le paramètre grades dans la classe Student), ils doivent être capturés afin de rester présents après l'exécution du constructeur. Ceci est similaire à la façon dont les paramètres et les variables locales sont capturés dans les expressions lambda. Pour les paramètres du constructeur primaire, la capture est mise en œuvre en générant un champ de soutien privé sur la classe ou la structure elle-même. Le champ a un nom "unspeakable", ce qui signifie qu'il n'entrera pas en collision avec d'autres noms et qu'il n'est pas évident par réflexion. Réfléchissez à la manière dont vous affectez et utilisez les paramètres du constructeur primaire afin d'éviter le double stockage. Par exemple, name est utilisé pour initialiser l'auto-propriété Name, qui possède son propre champ d'appui. Si un autre membre faisait directement référence au paramètre name, ce dernier serait également stocké dans son propre champ de sauvegarde, ce qui entraînerait une duplication regrettable.

Une classe dotée d'un constructeur primaire peut avoir des constructeurs supplémentaires. Ces derniers doivent utiliser un initialisateur this(...) pour appeler un autre constructeur sur la même classe ou structure. Cela permet de s'assurer que le constructeur primaire est toujours appelé et que toutes les données nécessaires à la création de la classe sont présentes. Une structure possède toujours un constructeur sans paramètre. Le constructeur implicite sans paramètre n'utilise pas d'initialisateur this()pour appeler le constructeur primaire. Dans le cas d'une struct, vous devez écrire un constructeur sans paramètre explicite pour faire en sorte que le constructeur primaire soit appelé.

Directives d'utilisation pour les types supplémentaires

C# 12 étend la prise en charge des directives d'utilisation à n'importe quel type. Voici quelques exemples :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
using Measurement = (string, int);
using PathOfPoints = int[];
using DatabaseInt = int?;

Il est désormais possible de définir des alias pour presque tous les types. Vous pouvez créer des alias pour les types valeur nullable, mais vous ne pouvez pas créer d'alias pour les types référence nullable. Les tuples sont particulièrement intéressants car ils permettent d'inclure des noms et des types d'éléments :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
using Measurement = (string Units, int Distance);

Vous pouvez utiliser des alias partout où vous utiliseriez un type, par exemple :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
public void F(Measurement x)
 
{ }

Les alias vous permettent de faire abstraction des types que vous utilisez et de donner des noms conviviaux à des noms génériques longs ou confus. Cela peut faciliter la lecture de votre code.

Valeurs par défaut pour les expressions lambda

C# 12 franchit une nouvelle étape dans l'autonomisation des expressions lambda en vous permettant de spécifier des valeurs par défaut pour les paramètres. La syntaxe est la même que pour les autres paramètres par défaut :


Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
var addWithDefault = (int addTo = 2) => addTo + 1;
addWithDefault(); // 3
addWithDefault(5); // 6

Comme pour les autres valeurs par défaut, la valeur par défaut sera émise dans les métadonnées et sera disponible par réflexion en tant que DefaultValue du ParameterInfo de la propriété Method de l'expression lambda. Par exemple :


Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
var addWithDefault = (int addTo = 2) => addTo + 1;
addWithDefault.Method.GetParameters()[0].DefaultValue; // 2

Avant C# 12, vous deviez utiliser une fonction locale ou la difficile DefaultParameterValue de l'espace de noms System.Runtime.InteropServices pour fournir une valeur par défaut aux paramètres de l'expression lambda. Ces approches fonctionnent toujours, mais elles sont plus difficiles à lire et ne sont pas cohérentes avec les valeurs par défaut des méthodes. Avec les nouvelles valeurs par défaut des lambdas, vous aurez un aspect cohérent pour les valeurs des paramètres par défaut des méthodes, des constructeurs et des expressions lambda.

Prochaines étapes

Nous espérons que vous téléchargerez l'aperçu et que vous découvrirez ces fonctionnalités. Nous expérimentons en C# 12 avec un numéro dédié pour chaque fonctionnalité. Nous espérons que cela permettra de concentrer les commentaires et de faciliter l'adoption de ce que les autres disent.

Nous attendons vos commentaires avec impatience !

Source : Microsoft

Et vous ?

Que pensez-vous de ces nouvelles fonctionnalités de C# 12 ?

Voir aussi

Un premier aperçu des fonctionnalités de C# 11 est disponible avec la vérification des paramètres null, et les motifs de liste

Microsoft annonce la sortie de C# 10 dans le cadre de .NET 6 et Visual Studio 2022. C# 10 apporte des améliorations aux expressions lambda et plusieurs fonctionnalités

Une nouvelle Preview de C# 11 est disponible et s'accompagne d'une amélioration de l'initialisation des objets, ainsi que du support mathématique générique