paramètres de ref readonly
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 .
Résumé
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 | paramètre ref |
paramètre ref readonly |
paramètre in |
paramètre out |
---|---|---|---|---|
ref |
Autorisé | Autorisé | Avertissement | Erreur |
in |
Erreur | Autorisé | Autorisé | Erreur |
out |
Erreur | Erreur | Erreur | Autorisé |
Aucune annotation | Erreur | Avertissement | Autorisé | Erreur |
(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 | paramètre ref |
paramètre ref readonly |
paramètre in |
paramètre out |
---|---|---|---|---|
rvalue | Erreur | Avertissement | Autorisé | Erreur |
lvalue | Autorisé | Autorisé | Autorisé | Autorisé |
Où lvalue signifie une variable (c’est-à-dire une valeur avec un emplacement ; n’a pas besoin d’être accessible en écriture/assignable) et rvalue signifie 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 peuvent migrer vers des paramètres ref readonly
sans interrompre les utilisateurs.
Pour plus d’informations sur la compatibilité binaire, consultez l'encodage de métadonnées proposé.
Plus précisément, modification
-
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 déléguées.
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ée pour les paramètres d’indexeur (comme in
mais contrairement à ref
), mais non autorisé pour les paramètres d’opérateur (comme ref
mais 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 dans lequel les méthodes avec in
paramètre correspondent aux appels avec l’argument correspondant marqué comme ref
: cette modification sera contrôlée 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é.
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éthodes
De même, à des fins de fonction anonyme [§10.7] et de groupe de méthodes [§10.8] conversions, 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é.
Par 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 implicites de pointeur de fonction 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ées sans avertissements.
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 partial
déclaration avec son implémentation et lors de la correspondance de la signature d’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
. En C# 7.3 et versions ultérieures, elles sont également émises avec[in]
et, si elles sont virtuelles,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 sont émis avec modreq(System.Runtime.InteropServices.InAttribute)
pour garantir la compatibilité binaire avec les paramètres in
.
Notez que contrairement aux paramètres in
, aucune [IsReadOnly]
n’est émise pour les paramètres ref readonly
afin d’éviter d’augmenter la taille des métadonnées et de faire en sorte que les versions antérieures du compilateur interprètent ref readonly
paramètres en tant que paramètres ref
(et par conséquent, ref
→ ref readonly
ne sera pas un changement cassant 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 est une erreur si elle est appliquée à un paramètre, de la même façon que ParamArrayAttribute
.
Pointeurs de 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 ignorent les modopt
et interprètent donc les paramètres ref readonly
comme des paramètres ref
(cohérents avec un comportement de compilateur plus ancien 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 les modopt
l’utiliseront pour reconnaître les paramètres ref readonly
pour émettre des avertissements pendant les conversions et les 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’un saut binaire pour modifier les modificateurs dans les signatures de pointeur de fonction s’ils font partie des API publiques. Il s’agit donc d’un saut binaire lors de la modification de ref
ou de in
sur 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 sauts pour les appels de méthode, mais étant donné qu’ils sont provoqués par des modifications de résolution de surcharge, ils peuvent être déclenchés de la même façon pour les conversions de méthode.
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 ne permet pas aux auteurs d’API de modifier les signatures des API existantes qui ont choisi d’utiliser des paramètres ref
pour interdire les valeurs rvalues.
Les appelants de ces API doivent 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 peut 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, notant que la principale motivation des paramètres ref readonly
sont des API qui capturent ou retournent des références à partir de ces paramètres, de sorte que le marqueur d’un certain 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 cela, car nous perdrions la possibilité de modifier les API existantes sans interrompre 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 passent de ref
à ref readonly
.
En outre, in
a été redéfini comme ref readonly
+ 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 en C# 12. Ils restent des propositions potentielles.
déclarations de paramètres
L’ordre inverse des modificateurs (readonly ref
au lieu de ref readonly
) peut être autorisé.
Cela serait incohérent avec la façon dont readonly ref
retourne et les champs se comportent (l’ordre inverse est interdit ou signifie quelque chose de différent, respectivement) et pourrait se heurter à des paramètres en lecture seule s’ils sont implémentés à l’avenir.
Les valeurs de paramètre par défaut peuvent ê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, des modreq
spéciales peuvent être utilisées 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.
En outre, ils autorisent uniquement le modificateur de ref
contrairement aux arguments qui autorisent également in
, donc in
et ref
deviennent interchangeables pour les arguments, ou in
devient pratiquement obsolète si les utilisateurs veulent rendre leur code cohérent (ils utiliseraient probablement ref
partout, car il s’agit du seul modificateur autorisé pour les affectations de référence 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 ref readonly
récepteur peut entraîner l’avertissement « L’argument 1 doit être passé avec ref
ou le mot clé in
», comme cela se produit pour les appels non d’extension sans modificateurs d’appel de site d’appel (l’utilisateur peut corriger ce type d’avertissement en transformant l’appel de méthode d’extension en appel de méthode statique).
Le même avertissement peut être signalé lors de l’utilisation d’un initialiseur de collection personnalisé ou d’un gestionnaire de chaînes interpolé avec ref readonly
paramètre, 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
de in
dans les signatures déléguées sans interrompre leurs utilisateurs (de manière cohérente avec ce qui est autorisé pour les signatures de méthode 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 des RequiresLocationAttribute
dans la source peut être autorisée, de la même façon que les attributs In
et Out
.
Il peut également s’agir d’une erreur lorsqu’elle est appliquée dans d’autres contextes que des paramètres uniquement, de la même façon que 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 |
changement binaire incompatible, changement source incompatible | d’accord |
modreq(RequiresLocation) |
oui | non pris en charge | changement binaire incompatible, changement source incompatible | binaire, rupture de source |
modopt(RequiresLocation) |
oui | ref |
rupture binaire | changement binaire incompatible, changement source incompatible |
Nous pourrions émettre des 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 pour LangVersion <= 11
différent du comportement des versions antérieures du compilateur.
Par exemple, il peut s’agir d’une erreur chaque fois qu’un paramètre ref readonly
est appelé (même lors de l’utilisation du modificateur ref
au niveau de l’appel), ou il peut 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 l’atténuer en
- interdire l’incompatibilité
ref
/in
(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 meilleureté pourraient marquer comme pire le paramètre dont l’argument aurait pu être passé avec un modificateur d’argument différent pour le rendre meilleur.
En d’autres termes, l’utilisateur doit toujours être en mesure de transformer un paramètre pire en un meilleur paramètre 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 peut transmettre l’argument par valeur pour choisir le paramètre in
.
Cette règle n’est qu’une extension de règle de préférence par valeur/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 aucun n’est pire que le paramètre correspondant d’une autre surcharge).
argument | meilleur paramètre | pire paramètre |
---|---|---|
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éthode 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 imprime 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);
Concevoir des réunions
- 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