Partager via


Nouveautés de C# 14

C# 14 inclut les nouvelles fonctionnalités suivantes. Vous pouvez essayer ces fonctionnalités à l’aide de la dernière version de Visual Studio 2026 ou du Kit de développement logiciel (SDK) .NET 10 :

C# 14 est la dernière version C#. C# 14 est pris en charge sur .NET 10. Pour plus d’informations, consultez Contrôle de version du langage C#.

Vous pouvez télécharger le dernier Kit de développement logiciel (SDK) .NET 10 à partir de la page de téléchargements .NET. Vous pouvez également télécharger Visual Studio 2026, qui inclut le Kit de développement logiciel (SDK) .NET 10.

Vous pouvez trouver tous les changements cassants introduits dans C# 14 dans notre article sur les changements cassants.

Remarque

Nous sommes intéressés par vos commentaires sur ces fonctionnalités. Si vous rencontrez des problèmes avec l’une de ces nouvelles fonctionnalités, créez un nouveau problème dans le référentiel dotnet/roslyn.

Membres de l’extension

C# 14 ajoute une nouvelle syntaxe pour définir des membres d’extension. La nouvelle syntaxe vous permet de déclarer des propriétés d’extension en plus des méthodes d’extension. Vous pouvez également déclarer des membres d’extension qui étendent le type, plutôt qu’une instance du type. En d’autres termes, ces nouveaux membres d’extension peuvent apparaître en tant que membres statiques du type que vous étendez. Ces extensions peuvent inclure des opérateurs définis par l’utilisateur implémentés en tant que méthodes d’extension statiques. L’exemple de code suivant montre un exemple des différents types de membres d’extension que vous pouvez déclarer :

public static class Enumerable
{
    // Extension block
    extension<TSource>(IEnumerable<TSource> source) // extension members for IEnumerable<TSource>
    {
        // Extension property:
        public bool IsEmpty => !source.Any();

        // Extension method:
        public IEnumerable<TSource> Where(Func<TSource, bool> predicate) { ... }
    }

    // extension block, with a receiver type only
    extension<TSource>(IEnumerable<TSource>) // static extension members for IEnumerable<Source>
    {
        // static extension method:
        public static IEnumerable<TSource> Combine(IEnumerable<TSource> first, IEnumerable<TSource> second) { ... }

        // static extension property:
        public static IEnumerable<TSource> Identity => Enumerable.Empty<TSource>();

        // static user defined operator:
        public static IEnumerable<TSource> operator + (IEnumerable<TSource> left, IEnumerable<TSource> right) => left.Concat(right);
    }
}

Les membres du premier bloc d’extension sont appelés comme s’ils sont des membres d’instance de IEnumerable<TSource>, par exemple sequence.IsEmpty. Les membres du deuxième bloc d’extension sont appelés comme s’ils sont des membres statiques de IEnumerable<TSource>, par exemple IEnumerable<int>.Identity.

Vous pouvez en savoir plus en lisant l’article sur les membres de l’extension dans le guide de programmation, l’article de référence de langage sur le extension mot clé et la spécification des fonctionnalités pour la nouvelle fonctionnalité des membres d’extension.

Mot clé field

Le jeton field vous permet d’écrire un corps d’accesseur de propriété sans déclarer de champ de stockage explicite. Le jeton field est remplacé par un champ de stockage synthétisé par un compilateur.

Par exemple, auparavant, si vous souhaitiez vous assurer qu’une propriété string ne pouvait pas être définie sur null, vous deviez déclarer un champ de stockage et implémenter les deux accesseurs.

private string _msg;
public string Message
{
    get => _msg;
    set => _msg = value ?? throw new ArgumentNullException(nameof(value));
}

Vous pouvez maintenant simplifier votre code pour :

public string Message
{
    get;
    set => field = value ?? throw new ArgumentNullException(nameof(value));
}

Vous pouvez déclarer un corps pour un accesseur ou les deux accesseurs d’une propriété stockée dans un champ.

Il existe un risque de changement cassant ou de confusion lors de la lecture de code dans les types qui incluent également un symbole nommé field. Vous pouvez utiliser @field ou this.field lever l’ambiguïté entre le field mot clé et l’identificateur, ou renommer le symbole actuel field pour fournir une meilleure distinction.

Conversions de portée implicites

C# 14 introduit la prise en charge de première classe pour System.Span<T> et System.ReadOnlySpan<T> dans le langage. Cette prise en charge implique de nouvelles conversions implicites permettant une programmation plus naturelle avec ces types.

Span<T> et ReadOnlySpan<T> sont utilisés de nombreuses façons clés en C# et au runtime. Leur introduction améliore les performances sans risquer la sécurité. C# 14 reconnaît la relation et prend en charge certaines conversions entre ReadOnlySpan<T>, Span<T>et T[]. Les types d’étendues peuvent être des récepteurs de méthode d’extension, se combiner avec d’autres conversions et faciliter des scénarios d’inférence de types génériques.

Vous trouverez la liste des conversions d’étendue implicites dans l’article sur les types intégrés dans la section de référence du langage. Vous pouvez en savoir plus de détails en lisant la spécification de la fonctionnalité pour les types d’étendue de première classe.

Types génériques non liés et nameof

À partir de C# 14, l’argument à nameof peut être un type générique non lié. Par exemple, nameof(List<>) a pour résultat List. Dans les versions antérieures de C#, seuls les types génériques fermés, tels que List<int>, peuvent être utilisés pour retourner le List nom.

Paramètres lambda simples avec modificateurs

Vous pouvez ajouter des modificateurs de paramètre, tels que scoped, , refin, outou ref readonly à des paramètres d’expression lambda sans spécifier le type de paramètre :

delegate bool TryParse<T>(string text, out T result);
// ...
TryParse<int> parse1 = (text, out result) => Int32.TryParse(text, out result);

Auparavant, l’ajout de modificateurs n’était autorisé que lorsque les déclarations de paramètres incluaient les types des paramètres. La déclaration précédente nécessite des types sur tous les paramètres :

TryParse<int> parse2 = (string text, out int result) => Int32.TryParse(text, out result);

Le params modificateur nécessite toujours une liste de paramètres typée explicitement.

Vous pouvez en savoir plus sur ces modifications dans l’article sur les expressions lambda dans la référence du langage C#.

Plus de membres partiels

Vous pouvez maintenant déclarer les constructeurs d’instances et les événements en tant que membres partiels.

Les constructeurs partiels et les événements partiels doivent inclure exactement une déclaration de définition et une déclaration d’implémentation.

Seule la déclaration d’implémentation d’un constructeur partiel peut inclure un initialiseur de constructeur : this() ou base(). Une seule déclaration de type partiel peut inclure la syntaxe du constructeur principal.

La déclaration d’implémentation d’un événement partiel doit inclure les accesseurs add et remove. La déclaration de définition déclare un événement de type champ.

Affectation composée définie par l’utilisateur

Vous pouvez en savoir plus dans la spécification de fonctionnalité pour l’affectation composée définie par l’utilisateur.

Affectation conditionnelle nulle

Les opérateurs d’accès de membre conditionnel null, ?. et ?[], peuvent désormais être utilisés sur le côté gauche d'une affectation ou d'une affectation composée.

Avant C# 14, vous devez vérifier null une variable avant de l’affecter à une propriété :

if (customer is not null)
{
    customer.Order = GetCurrentOrder();
}

Vous pouvez simplifier le code précédent à l’aide de l’opérateur ?. :

customer?.Order = GetCurrentOrder();

Le côté droit de l’opérateur = est évalué uniquement lorsque le côté gauche n’est pas null. Si customer est nul, le code n’appelle pas GetCurrentOrder.

En plus de l’affectation, vous pouvez utiliser des opérateurs d’accès membre conditionnel null avec des opérateurs d’affectation composée (+=et -=d’autres). Cependant, l'incrémentation et la décrémentation, ++ et --, ne sont pas autorisées.

Vous pouvez en savoir plus dans l’article de référence du langage sur l’accès aux membres conditionnels et la spécification de fonctionnalité pour l’attribution conditionnelle null.

Voir aussi