Partage via


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 que in ne soient disponibles et passer à in constituerait un changement source et binaire incompatible, par exemple QueryInterface, 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 exemple ReadOnlySpan<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 exemple Unsafe.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

  • refref readonly ne constituerait qu’un changement binaire incompatible pour les méthodes virtuelles,
  • refin 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 arguments ref passés aux paramètres in),
  • inref 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ètres ref, interdisant in ou aucune annotation au point d’appel) et les nouvelles versions de compilateur avec LangVersion <= 11 (pour la cohérence avec les versions de compilateur plus anciennes, une erreur sera émise 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).

Dans le sens inverse, changer

  • ref readonlyref pourrait constituer un changement source incompatible (sauf si seule une annotation de point d’appel ref é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 readonlyin ne serait pas un changement disruptif (mais l'annotation au site d'appel ref 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 sont les mêmes que celles spécifiées pour les paramètres dans leur propositionde , sauf modifications explicitement indiquées dans cette proposition.

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ètre ref readonly ou, en fonction de LangVersion, au paramètre ref du délégué.
  • Remarque : le paramètre ref de la méthode cible n’est pas autorisé à correspondre au paramètre in ni au paramètre ref 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 avec System.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 refref 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 inref 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 refref readonly inref 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, inref readonly ne constituerait pas un changement incompatible même pour les anciennes versions de compilateur, mais refref 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 vers in pour les anciennes API qui utilisaient ref car in 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).
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