Partager via


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 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 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

  • 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 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 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é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è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é.

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 avec System.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, refref 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 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 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 refref readonly inref 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, 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 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 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 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