Paramètres ref readonly
Remarque
Cet article est une spécification de fonctionnalité. La spécification sert de document de conception pour la fonctionnalité. Elle inclut les changements de spécification proposés, ainsi que les informations nécessaires à la conception et au développement de la fonctionnalité. Ces articles sont publiés jusqu'à ce que les changements proposés soient finalisés et incorporés dans la spécification ECMA actuelle.
Il peut y avoir des différences entre la spécification de la fonctionnalité et l'implémentation réalisée. Ces différences sont consignées dans les notes pertinentes de la réunion de conception linguistique (LDM).
Pour en savoir plus sur le processus d'adoption des speclets de fonctionnalité dans la norme du langage C#, consultez l'article sur les spécifications.
Problème de champion : https://github.com/dotnet/csharplang/issues/6010
Récapitulatif
Autoriser le modificateur de déclaration de paramètre ref readonly
et modifier les règles de site d'appel comme suit :
Annotation de point d’appel | ref paramètre |
ref readonly paramètre |
in paramètre |
out paramètre |
---|---|---|---|---|
ref |
Autorisé | Autorisé | Avertissement | Error |
in |
Error | Autorisé | Autorisé | Error |
out |
Error | Erreur | Error | Autorisé |
Aucune annotation | Error | Avertissement | Autorisé | Error |
(Remarque qu'il y a une modification des règles existantes : le paramètre in
avec l'annotation d’appel ref
produit un avertissement au lieu d'une erreur.)
Modifiez les règles de valeur d’argument comme suit :
Type de valeur | ref paramètre |
ref readonly paramètre |
in paramètre |
out paramètre |
---|---|---|---|---|
rvalue | Error | Avertissement | Autorisé | Error |
lvalue | Autorisé | Autorisé | Autorisé | Autorisé |
Où lvalue désigne une variable (c’est-à-dire une valeur avec un emplacement ; n’a pas besoin d’être accessible en écriture/assignable) et rvalue désigne n’importe quel type de valeur.
Motivation
C# 7.2 introduit des paramètres in
comme moyen de passer des références en lecture seule.
Les paramètres in
permettent à la fois les lvalues et les rvalues et peuvent être utilisés sans aucune annotation au point d’appel.
Toutefois, les API qui capturent ou retournent des références à partir de leurs paramètres souhaitent interdire les rvalues et fournir également une indication au niveau de l'appel pour indiquer qu'une référence est capturée.
Les paramètres ref readonly
sont idéaux dans de tels cas car ils avertissent s’ils sont utilisés avec des rvalues ou sans aucune annotation au point d’appel.
De plus, il existe des API qui nécessitent uniquement des références en lecture seule mais utilisent
- des paramètres
ref
car ils ont été introduits avant quein
ne soient disponibles et passer àin
constituerait un changement source et binaire incompatible, par exempleQueryInterface
, ou - des paramètres
in
pour accepter des références en lecture seule même si leur passage de rvalues n’a pas vraiment de sens, par exempleReadOnlySpan<T>..ctor(in T value)
, ou - des paramètres
ref
pour interdire les rvalues même s’ils ne modifient pas la référence passée, par exempleUnsafe.IsNullRef
.
Ces API pourraient migrer vers des paramètres ref readonly
sans perturber les utilisateurs.
Pour plus d’informations sur la compatibilité binaire, consultez l'encodage de métadonnées proposé.
Plus précisément, changer
ref
→ref readonly
ne constituerait qu’un changement binaire incompatible pour les méthodes virtuelles,ref
→in
serait également un changement binaire incompatible pour les méthodes virtuelles, mais pas un changement source incompatible (car les règles changent pour n’avertir que pour les argumentsref
passés aux paramètresin
),in
→ref readonly
ne constituerait pas un changement incompatible (mais aucune annotation de point d’appel ou rvalue entraînerait un avertissement),- notez que cela constituerait un changement source incompatible pour les utilisateurs utilisant des versions de compilateur plus anciennes (car ils interprètent les paramètres
ref readonly
comme des paramètresref
, interdisantin
ou aucune annotation au point d’appel) et les nouvelles versions de compilateur avecLangVersion <= 11
(pour la cohérence avec les versions de compilateur plus anciennes, une erreur sera émise indiquant que les paramètresref readonly
ne sont pas pris en charge sauf si les arguments correspondants sont passés avec le modificateurref
).
- notez que cela constituerait un changement source incompatible pour les utilisateurs utilisant des versions de compilateur plus anciennes (car ils interprètent les paramètres
Dans le sens inverse, changer
ref readonly
→ref
pourrait constituer un changement source incompatible (sauf si seule une annotation de point d’appelref
était utilisée et que seules des références en lecture seule étaient utilisées comme arguments), et un changement binaire incompatible pour les méthodes virtuelles,ref readonly
→in
ne serait pas un changement disruptif (mais l'annotation au site d'appelref
entraînerait un avertissement).
Notez que les règles décrites ci-dessus s’appliquent aux signatures de méthode, mais pas aux signatures de délégué.
Par exemple, le changement de ref
en in
dans une signature de délégué peut être un changement qui casse le code source (si un utilisateur affecte une méthode avec un paramètre ref
à ce type de délégué, cela provoquerait une erreur après la modification de l'API).
Conception détaillée
En règle générale, les règles concernant les paramètres
Déclarations de paramètres
Aucune modification de la grammaire n’est nécessaire.
Le modificateur ref readonly
sera autorisé pour les paramètres.
Outre les méthodes normales, ref readonly
sera autorisé pour les paramètres d’indexeur (comme in
et contrairement à ref
), mais interdit pour les paramètres d’opérateur (comme ref
et contrairement à in
).
Les valeurs par défaut des paramètres seront autorisées pour les paramètres ref readonly
avec un avertissement car elles sont équivalentes au passage de rvalues.
Cela permet aux auteurs d’API de modifier les paramètres in
avec des valeurs par défaut en paramètres ref readonly
sans introduire de modification rompant la source.
Vérifications du type de valeur
Notez que même si le modificateur d’argument ref
est autorisé pour les paramètres ref readonly
, rien ne change en ce qui concerne les vérifications de type valeur, c’est-à-dire,
-
ref
ne peut être utilisé qu’avec des valeurs assignables ; - Pour passer des références en lecture seule, il faut plutôt utiliser le modificateur d’argument
in
. - pour passer des rvalues, il faut ne pas utiliser de modificateur (ce qui entraîne un avertissement pour les paramètres
ref readonly
comme décrit dans le résumé de cette proposition).
Résolution de surcharge
La résolution de surcharge permettra de mélanger ref
/ref readonly
/in
/aucune annotation de point d’appel et modificateurs de paramètres comme indiqué dans le tableau du résumé de cette proposition, c’est-à-dire que tous les cas autorisés et avec un avertissement seront considérés comme des candidats possibles lors de la résolution de surcharge.
Plus précisément, il existe un changement de comportement existant où les méthodes avec un paramètre in
correspondront aux appels avec l’argument correspondant marqué comme ref
(ce changement sera basé sur LangVersion).
Cependant, l’avertissement pour le passage d’un argument sans modificateur de point d’appel à un paramètre ref readonly
sera supprimé si le paramètre est
- le récepteur dans une invocation de méthode d’extension,
- utilisé implicitement dans le cadre d’un initialiseur de collection personnalisé ou d’un gestionnaire de chaînes interpolées.
Les surcharges par valeur sont préférées aux surcharges ref readonly
lorsqu'il n'y a pas de modificateur d'argument (les paramètresin
ont le même comportement).
Conversions de méthode
De même, dans le cadre des conversions de fonctions anonymes [§10.7] et de groupes de méthodes [§10.8], ces modificateurs sont considérés comme compatibles (mais toute conversion autorisée entre différents modificateurs entraîne un avertissement) :
- Le paramètre
ref readonly
de la méthode cible est autorisé à correspondre àin
ou àref
, paramètre du délégué. - Le paramètre
in
de la méthode cible est autorisé à correspondre au paramètreref readonly
ou, en fonction de LangVersion, au paramètreref
du délégué. - Remarque : le paramètre
ref
de la méthode cible n’est pas autorisé à correspondre au paramètrein
ni au paramètreref readonly
du délégué.
Exemple :
DIn dIn = (ref int p) => { }; // error: cannot match `ref` to `in`
DRef dRef = (in int p) => { }; // warning: mismatch between `in` and `ref`
DRR dRR = (ref int p) => { }; // error: cannot match `ref` to `ref readonly`
dRR = (in int p) => { }; // warning: mismatch between `in` and `ref readonly`
dIn = (ref readonly int p) => { }; // warning: mismatch between `ref readonly` and `in`
dRef = (ref readonly int p) => { }; // warning: mismatch between `ref readonly` and `ref`
delegate void DIn(in int p);
delegate void DRef(ref int p);
delegate void DRR(ref readonly int p);
Notez qu’il n’y a aucun changement dans le comportement des conversions de pointeurs de fonction. En guise de rappel, les conversions de pointeurs de fonctions implicites ne sont pas autorisées s’il existe une incompatibilité entre les modificateurs de type de référence, et les casts explicites sont toujours autorisés sans avertissement.
Correspondance des signatures
Les membres déclarés dans un seul type ne peuvent pas différer dans la signature uniquement par ref
/out
/in
/ref readonly
.
Pour d’autres fins de correspondance des signatures (par exemple, masquer ou remplacer), ref readonly
peut être échangé avec le modificateur in
, mais cela entraîne un avertissement au site de déclaration [§7.6].
Cela ne s’applique pas lors de la mise en correspondance de la déclaration partial
avec son implémentation, et lors de la mise en correspondance de la signature de l’intercepteur avec la signature interceptée.
Notez qu'il n'y a aucune modification lors de la surcharge des paires de modificateurs ref
/in
et ref readonly
/ref
; elles ne peuvent pas être échangées car les signatures ne sont pas compatibles binaires.
Pour plus de cohérence, il en va de même pour d’autres fins de correspondance des signatures (par exemple, masquer).
Encodage des métadonnées
En guise de rappel,
- Les paramètres
ref
sont émis en tant que types byref simples (T&
en IL), - Les paramètres
in
sont similaires àref
et sont annotés avecSystem.Runtime.CompilerServices.IsReadOnlyAttribute
. Dans C# 7.3 et versions ultérieures, ces éléments sont également émis avec[in]
et, s’ils sont virtuels,modreq(System.Runtime.InteropServices.InAttribute)
.
Les paramètres ref readonly
seront émis en tant que [in] T&
, plus annotés avec l’attribut suivant :
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
public sealed class RequiresLocationAttribute : Attribute
{
}
}
En outre, s’ils sont virtuels, ils seront émis avec modreq(System.Runtime.InteropServices.InAttribute)
pour garantir la compatibilité binaire avec les paramètres in
.
Notez que contrairement aux paramètres in
, aucun [IsReadOnly]
ne sera émis pour les paramètres ref readonly
afin d’éviter d’augmenter la taille des métadonnées et également pour que les versions antérieures du compilateur interprètent les paramètres ref readonly
comme des paramètres ref
(et donc ref
→ ref readonly
ne sera pas une modification de changement cassant de source, même entre différentes versions du compilateur).
Le RequiresLocationAttribute
sera associé par nom qualifié par l’espace de noms et synthétisé par le compilateur s’il n’est pas déjà inclus dans la compilation.
La spécification de l’attribut dans la source sera une erreur si elle est appliquée à un paramètre, de manière similaire à ParamArrayAttribute
.
Pointeurs fonction
Dans les pointeurs de fonction, les paramètres in
sont émis avec modreq(System.Runtime.InteropServices.InAttribute)
(voir la proposition concernant les pointeurs de fonction).
Les paramètres ref readonly
seront émis sans ce modreq
, mais plutôt avec modopt(System.Runtime.CompilerServices.RequiresLocationAttribute)
.
Les versions antérieures du compilateur ignoreront le modopt
et interpréteront donc les paramètres ref readonly
comme des paramètres ref
(conformément au comportement des anciennes versions du compilateur pour les méthodes normales avec des paramètres ref readonly
comme décrit ci-dessus) et les nouvelles versions du compilateur prenant en charge le modopt
l’utiliseront pour reconnaître les paramètres ref readonly
afin d’émettre des avertissements lors des conversions et des appels.
Pour assurer la cohérence avec les versions antérieures du compilateur, les nouvelles versions du compilateur de LangVersion <= 11
signaleront des erreurs indiquant que les paramètres ref readonly
ne sont pas pris en charge, sauf si les arguments correspondants sont passés avec le modificateur ref
.
Notez qu’il s’agit d’une rupture binaire lorsque les modificateurs dans les signatures de pointeurs de fonction sont modifiés s’ils font partie des API publiques. Il y aura donc une rupture binaire lors du changement de ref
ou de in
en ref readonly
.
Toutefois, une interruption de source se produit uniquement pour les appelants avec LangVersion <= 11
lors du changement de in
→ ref readonly
(si vous invoquez le pointeur avec le modificateur de site d'appel in
), conformément aux méthodes normales.
Dernières modifications
La relaxation de la non-concordance de ref
/in
dans la résolution de surcharge introduit un changement de comportement incompatible démontré dans l’exemple suivant :
class C
{
string M(in int i) => "C";
static void Main()
{
int i = 5;
System.Console.Write(new C().M(ref i));
}
}
static class E
{
public static string M(this C c, ref int i) => "E";
}
En C# 11, l’appel est lié à E.M
, par conséquent "E"
est affiché.
En C# 12, C.M
est autorisé à se lier (avec un avertissement) et aucun scope d’extension n’est recherché puisque nous avons un candidat applicable, donc "C"
est affiché.
Il y a également un changement source incompatible pour la même raison.
L’exemple ci-dessous affiche "1"
en C# 11, mais échoue à compiler avec une erreur d’ambiguïté en C# 12 :
var i = 5;
System.Console.Write(C.M(null, ref i));
interface I1 { }
interface I2 { }
static class C
{
public static string M(I1 o, ref int x) => "1";
public static string M(I2 o, in int x) => "2";
}
Les exemples ci-dessus illustrent les ruptures pour les appels de méthode, mais étant donné qu’elles sont provoquées par des changements de résolution de surcharge, elles peuvent être déclenchées de manière similaire pour les conversions de méthodes.
Alternatives
Déclarations de paramètres
Les auteurs d'API peuvent annoter les paramètres in
conçus pour n'accepter que les lvalues avec un attribut personnalisé et fournir un analyseur pour signaler les utilisations incorrectes.
Cela n’autoriserait pas les auteurs d’API à modifier les signatures des API existantes qui ont choisi d’utiliser les paramètres ref
pour interdire les rvalues.
Les appelants de ces API devront toujours effectuer un travail supplémentaire pour obtenir un ref
s’ils n’ont accès qu’à une variable ref readonly
.
Changer ces API de ref
à [RequiresLocation] in
constituerait un changement source incompatible (et dans le cas des méthodes virtuelles, également un changement binaire incompatible).
Au lieu d’autoriser le modificateur ref readonly
, le compilateur pourrait reconnaître lorsqu’un attribut spécial (comme [RequiresLocation]
) est appliqué à un paramètre.
Cela a été abordé dans LDM 2022-04-25, décidant qu’il s’agit d’une fonctionnalité linguistique, et non d’un analyseur, il doit donc ressembler à une telle fonctionnalité.
Vérifications du type de valeur
Passer des lvalues sans aucun modificateur aux paramètres ref readonly
pourrait être autorisé sans avertissements, de manière similaire aux paramètres byref implicites de C++.
Cela a été abordé dans LDM 2022-05-11, en notant que la principale motivation pour les paramètres ref readonly
sont les API qui capturent ou retournent des références à partir de ces paramètres, de sorte qu’un marqueur de ce type est une bonne chose.
Passer une rvalue à un ref readonly
pourrait être une erreur, pas un avertissement.
Cela a été initialement accepté dans LDM 2022-04-25, mais les discussions par e-mail ultérieures ont assoupli cette position, car nous perdrions la possibilité de modifier les API existantes sans perturber les utilisateurs.
in
pourrait être le modificateur de site d'appel « naturel » pour les paramètres de ref readonly
et l’utilisation de ref
peut entraîner des avertissements.
Cela garantirait un style de code cohérent et rendrait évident au point d'invocation que la référence est en lecture seule (contrairement à ref
).
Cela a été initialement accepté dans LDM 2022-04-25.
Toutefois, les avertissements peuvent être un point de friction pour que les auteurs d’API lors du passage de ref
à ref readonly
.
En outre, in
a été redéfini comme ref readonly
+ des fonctionnalités pratiques, ce qui a été rejeté dans LDM 2022-05-11.
En attente de révision LDM
Aucune des options suivantes n’a été implémentée dans C# 12. Elles restent des propositions potentielles.
Déclarations de paramètres
L’ordre inverse des modificateurs (readonly ref
au lieu de ref readonly
) pourrait être autorisé.
Cela serait incohérent avec la façon dont readonly ref
retourne les résultats et dont les champs se comportent (l’ordre inverse est interdit ou désigne quelque chose de différent, respectivement), et cela pourrait entrer en conflit avec les paramètres readonly s’ils sont implémentés à l’avenir.
Les valeurs par défaut des paramètres pourraient être une erreur pour les paramètres ref readonly
.
Vérifications du type de valeur
Des erreurs pourraient être émises au lieu d’avertissements lors du passage de rvalues aux paramètres ref readonly
ou de la non-concordance entre les annotations de point d’appel et les modificateurs de paramètres.
De même, un modreq
spécial pourrait être utilisé au lieu d’un attribut pour s’assurer que les paramètres ref readonly
sont distincts des paramètres in
au niveau binaire.
Cela fournirait des garanties plus solides, ce qui serait bon pour les nouvelles API, mais empêcherait l’adoption dans les API d’exécution existantes qui ne peuvent pas introduire de changements incompatibles.
Les vérifications du type de valeur peuvent être assouplies pour permettre la transmission de références en mode lecture seule via ref
dans les paramètres in
/ref readonly
.
Cela serait similaire à la façon dont les affectations de référence et les retours ref fonctionnent aujourd’hui; elles permettent également de transmettre des références en lecture seule via le modificateur ref
sur l’expression source.
Cependant, le ref
est généralement proche de l’endroit où la cible est déclarée en tant que ref readonly
, il est donc clair que nous passons une référence en lecture seule, contrairement aux invocations dont les modificateurs d’arguments et de paramètres sont généralement éloignés.
De plus, ils autorisent uniquement le modificateur ref
, contrairement aux arguments qui autorisent également in
. Par conséquent in
et ref
deviendraient interchangeables pour les arguments, ou in
deviendrait pratiquement obsolète si les utilisateurs voulaient rendre leur code cohérent (ils utiliseraient probablement ref
partout, puisque c’est le seul modificateur autorisé pour les affectations ref et les retours ref).
Résolution de surcharge
La résolution de surcharge, la redéfinition et la conversion peuvent interdire l'interchangeabilité des modificateurs ref readonly
et in
.
Le changement de résolution de surcharge pour les paramètres in
existants pourrait être pris inconditionnellement (sans tenir compte de LangVersion), mais cela constituerait un changement incompatible.
L’appel d’une méthode d’extension avec le récepteur ref readonly
pourrait entraîner l’avertissement « L’argument 1 doit être passé avec le mot clé ref
ou in
», comme cela se produirait pour les appels hors extension sans modificateur de site d’appel (l’utilisateur pourrait corriger ce type d’avertissement en transformant l’appel de méthode d’extension en un appel de méthode statique).
Le même avertissement pourrait être signalé lors de l’utilisation d’un initialiseur de collection personnalisé ou d’un gestionnaire de chaînes interpolées avec le paramètre ref readonly
, même si l’utilisateur n’a pas pu le contourner.
Les surcharges ref readonly
pourraient être préférées aux surcharges par valeur lorsqu’il n’y a pas de modificateur de point d’appel ou il pourrait y avoir une erreur d’ambiguïté.
Conversions de méthode
Nous pourrions permettre au paramètre ref
de la méthode cible de correspondre aux paramètres in
et ref readonly
du délégué.
Cela permettrait aux auteurs d’API de changer, par exemple, ref
en in
dans les signatures de délégués sans perturber leurs utilisateurs (de manière cohérente avec ce qui est autorisé pour les signatures de méthodes normales).
Cependant, cela entraînerait également la violation suivante des garanties readonly
avec seulement un avertissement :
class Program
{
static readonly int f = 123;
static void Main()
{
var d = (in int x) => { };
d = (ref int x) => { x = 42; }; // warning: mismatch between `ref` and `in`
d(f); // changes value of `f` even though it is `readonly`!
System.Console.WriteLine(f); // prints 42
}
}
Les conversions de pointeurs de fonction pourraient avertir sur la non-concordance ref readonly
/ref
/in
, mais si nous voulions les conditionner sur LangVersion, un investissement d’implémentation significatif serait nécessaire car aujourd’hui les conversions de type n’ont pas besoin d’accéder à la compilation.
De plus, bien que la non-concordance soit actuellement une erreur, il est facile pour les utilisateurs d’ajouter un cast pour permettre la non-concordance s’ils le souhaitent.
Encodage des métadonnées
La spécification de RequiresLocationAttribute
dans la source pourrait être autorisée, de manière similaire aux attributs In
et Out
.
Alternativement, elle pourrait être une erreur lorsqu’elle est appliquée dans des contextes autres que des paramètres, de manière similaire à l’attribut IsReadOnly
, pour préserver un espace de conception supplémentaire.
Les paramètres du pointeur de fonction ref readonly
peuvent être émis avec différentes combinaisons de modopt
/modreq
(notez que « interruption de source » dans ce tableau signifie pour les appelants avec LangVersion <= 11
) :
Modificateurs | Peut être reconnu entre les compilations | Les anciens compilateurs les considèrent comme | ref → ref readonly |
in → ref readonly |
---|---|---|---|---|
modreq(In) modopt(RequiresLocation) |
oui | in |
binaire, rupture de source | changement binaire incompatible |
modreq(In) |
non | in |
binaire, rupture de source | OK |
modreq(RequiresLocation) |
oui | non pris en charge | binaire, rupture de source | binaire, rupture de source |
modopt(RequiresLocation) |
oui | ref |
changement binaire incompatible | binaire, rupture de source |
Nous pourrions émettre les attributs [RequiresLocation]
et [IsReadOnly]
pour les paramètres ref readonly
.
Alors, in
→ ref readonly
ne constituerait pas un changement incompatible même pour les anciennes versions de compilateur, mais ref
→ ref readonly
deviendrait un changement source incompatible pour les anciennes versions de compilateur (car elles interpréteraient ref readonly
comme in
, interdisant les modificateurs ref
) et les nouvelles versions de compilateur avec LangVersion <= 11
(pour la cohérence).
Nous pourrions rendre le comportement de LangVersion <= 11
différent de celui des versions de compilateurs antérieures.
Par exemple, cela pourrait être une erreur chaque fois qu’un paramètre ref readonly
est appelé (même lors de l’utilisation du modificateur ref
au niveau du site d’appel), ou cela pourrait toujours être autorisé sans aucune erreur.
Dernières modifications
Cette proposition suggère d’accepter un changement de comportement incompatible car il devrait être rare de le rencontrer, est conditionné par LangVersion, et les utilisateurs peuvent contourner le problème en appelant explicitement la méthode d’extension. Au lieu de cela, nous pourrions atténuer cela en
- interdisant l’incompatibilité
ref
/in
(ce qui empêcherait uniquement la migration versin
pour les anciennes API qui utilisaientref
carin
n’était pas encore disponible), - modifier les règles de résolution de surcharge pour continuer à rechercher une meilleure correspondance (déterminée par les règles de supériorité spécifiées ci-dessous) lorsqu’il y a une non-concordance de type ref introduite dans cette proposition,
- ou alternativement continuer uniquement pour une non-concordance
ref
vs.in
, pas pour les autres (ref readonly
vs.ref
/in
/par valeur).
- ou alternativement continuer uniquement pour une non-concordance
Règles de supériorité
L’exemple suivant génère actuellement trois erreurs d’ambiguïté pour les trois appels de M
.
Nous pourrions ajouter de nouvelles règles d'amélioration pour résoudre les ambiguïtés.
Cela résoudrait également le changement source incompatible décrit précédemment.
Une façon serait de faire en sorte que l'exemple imprime 221
(où le paramètre ref readonly
est associé à l'argument in
puisqu'il s'agit d'un avertissement de l'appeler sans modificateur, tandis que pour le paramètre in
, c'est autorisé).
interface I1 { }
interface I2 { }
class C
{
static string M(I1 o, in int i) => "1";
static string M(I2 o, ref readonly int i) => "2";
static void Main()
{
int i = 5;
System.Console.Write(M(null, ref i));
System.Console.Write(M(null, in i));
System.Console.Write(M(null, i));
}
}
De nouvelles règles de supériorité pourraient marquer comme pire le paramètre dont l’argument aurait pu être passé avec un modificateur d’argument différent pour l’améliorer.
En d’autres termes, l’utilisateur devrait toujours être en mesure de changer un paramètre pire en un paramètre meilleur en modifiant son modificateur d’argument correspondant.
Par exemple, lorsqu’un argument est passé par in
, un paramètre ref readonly
est préféré à un paramètre in
, car l’utilisateur pourrait transmettre l’argument by-value pour choisir le paramètre in
.
Cette règle n’est qu’une extension de la règle de préférence by-value/in
qui est en vigueur aujourd’hui (il s’agit de la dernière règle de résolution de surcharge et la surcharge entière est meilleure si l’un de ses paramètres est meilleur et qu’aucun n’est pire que le paramètre correspondant d’une autre surcharge).
argument | paramètre meilleur | paramètre pire |
---|---|---|
ref /in |
ref readonly |
in |
ref |
ref |
ref readonly /in |
par valeur | par valeur/in |
ref readonly |
in |
in |
ref |
Nous devons gérer les conversions de méthodes de la même façon.
L’exemple suivant génère actuellement deux erreurs d’ambiguïté pour les deux affectations de délégués.
De nouvelles règles d'amélioration pourraient préférer un paramètre de méthode dont le modificateur refness correspond au modificateur refness du paramètre de délégué cible correspondant, plutôt qu'un paramètre présentant une incompatibilité.
Par conséquent, l’exemple suivant afficherait 12
.
class C
{
void M(I1 o, ref readonly int x) => System.Console.Write("1");
void M(I2 o, ref int x) => System.Console.Write("2");
void Run()
{
D1 m1 = this.M;
D2 m2 = this.M; // currently ambiguous
var i = 5;
m1(null, in i);
m2(null, ref i);
}
static void Main() => new C().Run();
}
interface I1 { }
interface I2 { }
class X : I1, I2 { }
delegate void D1(X s, ref readonly int x);
delegate void D2(X s, ref int x);
Réunions de conception
- LDM 2022-04-25 : fonctionnalité acceptée
- LDM 2022-05-09 : discussion divisée en trois parties
- LDM 2022-05-11 : autorisé
ref
et aucune annotation de point d’appel pour les paramètresref readonly
C# feature specifications