Annotations de paramètre de type non contraintes
Remarque
Cet article est une spécification de fonctionnalité. La spécification sert de document de conception pour la fonctionnalité. Il inclut les modifications de spécification proposées, ainsi que les informations nécessaires pendant la conception et le développement de la fonctionnalité. Ces articles sont publiés jusqu’à ce que les modifications de spécification proposées soient finalisées et incorporées dans la spécification ECMA actuelle.
Il peut y avoir des différences entre la spécification de la fonctionnalité et l’implémentation terminée. Ces différences sont consignées dans les notes pertinentes de la réunion de conception linguistique (LDM).
Vous pouvez en savoir plus sur le processus d’adoption des speclets de fonctionnalités dans la norme de langage C# dans l’article sur les spécifications .
Problème de champion : https://github.com/dotnet/csharplang/issues/3297
Résumé
Autorisez les annotations nullables pour les paramètres de type qui ne sont pas limités aux types valeur ou aux types de référence : T?
.
static T? FirstOrDefault<T>(this IEnumerable<T> collection) { ... }
Annotation ?
En C#8, les annotations ?
ne pouvaient être appliquées qu'aux paramètres de type qui étaient explicitement restreints aux types de valeur ou aux types de référence.
En C#9, ?
annotations peuvent être appliquées à n’importe quel paramètre de type, quelles que soient les contraintes.
Sauf si un paramètre de type est explicitement limité aux types valeur, les annotations peuvent uniquement être appliquées dans un contexte #nullable enable
.
Si un paramètre de type T
est remplacé par un type référence, T?
représente une instance nullable de ce type de référence.
var s1 = new string[0].FirstOrDefault(); // string? s1
var s2 = new string?[0].FirstOrDefault(); // string? s2
Si T
est substituée à un type valeur, T?
représente une instance de T
.
var i1 = new int[0].FirstOrDefault(); // int i1
var i2 = new int?[0].FirstOrDefault(); // int? i2
Si T
est substituée à un type annoté U?
, T?
représente le type annoté U?
plutôt que U??
.
var u1 = new U[0].FirstOrDefault(); // U? u1
var u2 = new U?[0].FirstOrDefault(); // U? u2
Si T
est substituée à un type U
, T?
représente U?
, même dans un contexte de #nullable disable
.
#nullable disable
var u3 = new U[0].FirstOrDefault(); // U? u3
Pour les valeurs de retour, T?
équivaut à [MaybeNull]T
; pour les valeurs d’argument, T?
équivaut à [AllowNull]T
.
L’équivalence est importante lors de la substitution ou de l’implémentation d’interfaces à partir d’un assembly compilé avec C#8.
public abstract class A
{
[return: MaybeNull] public abstract T F1<T>();
public abstract void F2<T>([AllowNull] T t);
}
public class B : A
{
public override T? F1<T>() where T : default { ... } // matches A.F1<T>()
public override void F2<T>(T? t) where T : default { ... } // matches A.F2<T>()
}
Contrainte default
Pour la compatibilité avec le code existant où les méthodes génériques substituées et implémentées explicitement n’ont pas pu inclure de clauses de contrainte explicite, T?
dans une méthode substituée ou implémentée explicitement est traitée comme Nullable<T>
où T
est un type valeur.
Afin d'autoriser les annotations pour les paramètres de type limités aux types de référence, C#8 permettait les contraintes where T : class
et where T : struct
explicites sur la méthode remplacée ou implémentée de manière explicite.
class A1
{
public virtual void F1<T>(T? t) where T : struct { }
public virtual void F1<T>(T? t) where T : class { }
}
class B1 : A1
{
public override void F1<T>(T? t) /*where T : struct*/ { }
public override void F1<T>(T? t) where T : class { }
}
Pour autoriser les annotations pour les paramètres de type qui ne sont pas limités aux types référence ni aux types valeur, C#9 permet une nouvelle contrainte where T : default
.
class A2
{
public virtual void F2<T>(T? t) where T : struct { }
public virtual void F2<T>(T? t) { }
}
class B2 : A2
{
public override void F2<T>(T? t) /*where T : struct*/ { }
public override void F2<T>(T? t) where T : default { }
}
Il s'agit d'une erreur d'utiliser une contrainte default
autrement que pour une redéfinition de méthode ou une implémentation explicite.
C'est une erreur d'utiliser une contrainte de default
lorsque le paramètre de type correspondant dans une méthode substituée ou une méthode d'interface est contraint à un type de référence ou un type de valeur.
Concevoir des réunions
C# feature specifications