parametri ref readonly
Nota
Questo articolo è una specifica di funzionalità. La specifica funge da documento di progettazione per la funzionalità. Include le modifiche specifiche proposte, insieme alle informazioni necessarie durante la progettazione e lo sviluppo della funzionalità. Questi articoli vengono pubblicati fino a quando le modifiche specifiche proposte non vengono completate e incorporate nella specifica ECMA corrente.
Potrebbero verificarsi alcune discrepanze tra la specifica di funzionalità e l'implementazione completata. Tali differenze vengono acquisite nelle note pertinenti del language design meeting (LDM) .
Puoi trovare ulteriori informazioni sul processo di adozione degli speclet nello standard del linguaggio di programmazione C# leggendo l'articolo sulle specifiche di .
Problema principale: https://github.com/dotnet/csharplang/issues/6010
Sommario
Consenti il modificatore sul sito di dichiarazione del parametro ref readonly
e modifica le regole del sito di chiamata come segue:
Annotazione al punto di chiamata | parametro ref |
parametro ref readonly |
parametro in |
parametro out |
---|---|---|---|---|
ref |
Permesso | consentiti | Avviso | Errore |
in |
Errore | consentiti | Permesso | Errore |
out |
Errore | errore | Errore | Permesso |
Nessuna annotazione | Errore | Avvertimento | Permesso | Errore |
Si noti che c'è una modifica alle regole esistenti: il parametro in
con l'annotazione "callsite" ref
genera un avviso anziché un errore.
Modificare le regole del valore dell'argomento come indicato di seguito:
Tipo di valore | parametro ref |
parametro ref readonly |
parametro in |
parametro out |
---|---|---|---|---|
rvalue | Errore | Avviso | Permesso | Errore |
lvalue | Permesso | consentiti | Permesso | Permesso |
Dove lvalue indica una variabile (ad esempio, un valore con una posizione; non deve essere scrivibile/assegnabile) e rvalue significa qualsiasi tipo di valore.
Motivazione
C# 7.2 ha introdotto in
parametri per trasmettere riferimenti di sola lettura.
in
parametri consentono sia lvalue che rvalue e possono essere usati senza alcuna annotazione nel callsite.
Tuttavia, le API che acquisiscono o restituiscono riferimenti dai loro parametri desiderano impedire l'uso di rvalues e imporre anche un'indicazione al punto di chiamata che un riferimento viene acquisito.
ref readonly
parametri sono ideali in tali casi in quanto avvertono se usati con rvalue o senza alcuna annotazione al punto di chiamata.
Sono inoltre disponibili API che richiedono solo riferimenti di sola lettura, ma che usano
-
ref
parametri sin da quando sono stati introdotti prima chein
diventassero disponibili, e la modifica ain
comporterebbe un'interruzione a livello di codice sorgente e binario, ad esempioQueryInterface
, o -
in
parametri per accettare riferimenti di sola lettura anche se il passaggio di rvalue a tali parametri non ha senso, ad esempioReadOnlySpan<T>..ctor(in T value)
o -
ref
parametri per impedire rvalue anche se non modificano il riferimento passato, ad esempioUnsafe.IsNullRef
.
Queste API possono eseguire la migrazione a parametri ref readonly
senza interrompere gli utenti.
Per informazioni dettagliate sulla compatibilità binaria, vedere la codifica dei metadati proposta.
In particolare, cambiando
-
ref
→ref readonly
sarebbe solo una modifica binaria di rottura per i metodi virtuali, -
ref
→in
sarebbe anche una modifica binaria significativa per i metodi virtuali, ma non una modifica che interrompe il codice sorgente (perché le regole cambiano per avvisare solo sugli argomentiref
passati ai parametriin
), -
in
→ref readonly
non sarebbe una modifica di rilievo (ma l'assenza di un'annotazione del punto di chiamata o di un valore r genererebbe un avviso),- Si noti che si tratta di una modifica che provoca un'interruzione di origine per gli utenti che utilizzano versioni precedenti del compilatore (poiché interpretano i parametri
ref readonly
come parametriref
, non consentendoin
o nessuna annotazione nel callsite) e per le nuove versioni del compilatore conLangVersion <= 11
(per garantire la coerenza con le versioni precedenti del compilatore, verrà generato un errore se i parametriref readonly
non sono supportati a meno che gli argomenti corrispondenti siano passati con il modificatoreref
).
- Si noti che si tratta di una modifica che provoca un'interruzione di origine per gli utenti che utilizzano versioni precedenti del compilatore (poiché interpretano i parametri
Nella direzione opposta, cambiando
-
ref readonly
→ref
sarebbe potenzialmente una modifica che altera la compatibilità del codice sorgente (a meno che non sia stata utilizzata solo l'annotazione del sito di chiamataref
e utilizzati solo riferimenti di sola lettura come argomenti) e una modifica che altera la compatibilità binaria per i metodi virtuali, -
ref readonly
→in
non sarebbe una modifica che causa un'interruzione, ma l'annotazione al callsiteref
genererebbe un avviso.
Si noti che le regole descritte in precedenza si applicano alle firme dei metodi, ma non alle firme delegate.
Ad esempio, la modifica di ref
in in
in una firma del delegato può essere una breaking change nel codice sorgente (se un utente assegna un metodo con il parametro ref
a quel tipo di delegato, ciò genererebbe un errore dopo la modifica dell'API).
Progettazione dettagliata
In generale, le regole per i parametri di ref readonly
sono uguali a quelle specificate per i parametri in
in la loro proposta, ad eccezione del caso in cui sia stata modificata in modo esplicito in questa proposta.
Dichiarazioni di parametri
Non sono necessarie modifiche alla grammatica.
Il modificatore ref readonly
sarà consentito per i parametri.
Oltre ai metodi normali, ref readonly
sarà consentito per i parametri dell'indicizzatore (ad esempio in
ma diversamente da ref
), ma non consentiti per i parametri dell'operatore (ad esempio ref
ma diversamente da in
).
I valori dei parametri predefiniti saranno consentiti per i parametri ref readonly
con un avviso poiché sono equivalenti al passaggio di rvalue.
In questo modo gli autori di API possono modificare in
parametri con valori predefiniti in ref readonly
parametri senza introdurre una modifica che rompe la compatibilità con il sorgente.
Controlli dei tipi di valore
Si noti che anche se il modificatore di argomenti ref
è consentito per i parametri ref readonly
, non cambia nulla rispetto ai controlli del tipo di valore, cioè,
-
ref
può essere usato solo con valori assegnabili; - per passare riferimenti readonly, è necessario usare invece il modificatore di argomenti
in
; - per passare rvalue, è necessario non usare alcun modificatore (che genera un avviso per i parametri
ref readonly
come descritto in riepilogo di questa proposta).
Risoluzione dei sovraccarichi
La risoluzione dell'overload consentirà di combinare ref
/ref readonly
/in
/no callite annotazioni e modificatori di parametri indicati dalla tabella in riepilogo di questa proposta, ovvero tutte le consentite e casi di avviso verranno considerati come possibili candidati durante la risoluzione dell'overload.
In particolare, esiste una modifica del comportamento esistente in cui i metodi con in
parametro corrisponderanno alle chiamate con l'argomento corrispondente contrassegnato come ref
. Questa modifica verrà controllata in LangVersion.
Tuttavia, l'avviso per il passaggio di un argomento senza modificatore callsite a un parametro ref readonly
verrà soppresso se il parametro è
- il ricevitore in una chiamata al metodo di estensione
- usato in modo implicito come parte dell'inizializzatore di raccolta personalizzato o del gestore di stringhe interpolato.
Gli overload per valore saranno preferiti rispetto agli overload ref readonly
nel caso in cui non sia presente alcun modificatore dell'argomento (i parametriin
hanno lo stesso comportamento).
Conversioni di metodi
Analogamente, ai fini della funzione anonima [§10.7] e del gruppo di metodi [§10.8] le conversioni, questi modificatori sono considerati compatibili (ma qualsiasi conversione consentita tra modificatori diversi genera un avviso):
- Il parametro
ref readonly
del metodo di destinazione può corrispondere al parametroin
o al parametroref
del delegato. - Il parametro
in
del metodo di destinazione può corrispondere al parametroref readonly
o, in base alla versione del linguaggio, al parametroref
del delegato. - Nota:
ref
parametro del metodo di destinazione non è consentito corrispondere ain
néref readonly
parametro del delegato.
Per esempio:
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);
Si noti che non sono state apportate modifiche al comportamento delle conversioni dei puntatori a funzione . Come promemoria, le conversioni implicite del puntatore di funzione non sono consentite se esiste una mancata corrispondenza tra i modificatori del tipo di riferimento e i cast espliciti sono sempre consentiti senza avvisi.
Corrispondenza della firma
I membri dichiarati in un singolo tipo non possono differire in firma solo per ref
/out
/in
/ref readonly
.
Per altri scopi di abbinamento delle firme (ad esempio, nascondere o sovrascrivere), il modificatore ref readonly
può essere interscambiato con in
, ma ciò genera un avviso nel sito di dichiarazione [§7.6].
Ciò non si applica quando si abbina la dichiarazione di partial
alla relativa implementazione e quando si abbina la firma dell'intercettore con la firma intercettata.
Si noti che non esiste alcuna modifica nell'override per le coppie di modifica ref
/in
e ref readonly
/ref
, non possono essere interscambiate, perché le firme non sono compatibili con i file binari.
Per coerenza, lo stesso vale per altri scopi di confronto delle firme (ad esempio, per nascondere).
Codifica dei metadati
Come promemoria,
- I parametri
ref
vengono emessi come tipi byref semplici (T&
in IL). -
in
parametri sono simili aref
più vengono annotati conSystem.Runtime.CompilerServices.IsReadOnlyAttribute
. In C# 7.3 e versioni successive vengono generati anche con[in]
e, se virtuale,modreq(System.Runtime.InteropServices.InAttribute)
.
ref readonly
parametri verranno emessi come [in] T&
e annotati con il seguente attributo:
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
public sealed class RequiresLocationAttribute : Attribute
{
}
}
Inoltre, se virtuali, verranno emessi con modreq(System.Runtime.InteropServices.InAttribute)
per garantire la compatibilità binaria con i parametri in
.
Si noti che a differenza dei parametri in
, non verrà generato alcun [IsReadOnly]
per i parametri ref readonly
per evitare di aumentare le dimensioni dei metadati e anche per rendere le versioni meno recenti del compilatore interpretare i parametri ref readonly
come parametri ref
(e di conseguenza ref
→ ref readonly
non sarà una modifica che causa un'interruzione di origine anche tra versioni diverse del compilatore).
Il RequiresLocationAttribute
verrà confrontato con il nome completo dello spazio dei nomi e sintetizzato dal compilatore, se non è già incluso nella compilazione.
Se si specifica l'attributo nell'origine, verrà generato un errore se viene applicato a un parametro, in modo analogo a ParamArrayAttribute
.
Puntatori a funzione
Nei puntatori a funzione i parametri in
vengono generati con modreq(System.Runtime.InteropServices.InAttribute)
(vedere proposta di puntatori a funzione).
ref readonly
parametri verranno generati senza modreq
, ma con modopt(System.Runtime.CompilerServices.RequiresLocationAttribute)
.
Le versioni precedenti del compilatore ignoreranno il modopt
e quindi interpreteranno i parametri ref readonly
come parametri ref
(coerenti con il comportamento del compilatore meno recente per i metodi normali con parametri ref readonly
come descritto in precedenza) e le nuove versioni del compilatore che conoscono il modopt
lo useranno per riconoscere i parametri ref readonly
per generare avvisi durante le conversioni e chiamate.
Per coerenza con le versioni precedenti del compilatore, le nuove versioni del compilatore con LangVersion <= 11
segnaleranno errori quando i parametri ref readonly
non sono supportati, a meno che gli argomenti corrispondenti non vengano forniti con il modificatore ref
.
Si noti che si tratta di un'interruzione binaria per modificare i modificatori nelle firme del puntatore di funzione se fanno parte delle API pubbliche, di conseguenza sarà un'interruzione binaria quando si modifica ref
o in
in ref readonly
.
Tuttavia, si verificherà un'interruzione della sorgente solo per i chiamanti con LangVersion <= 11
quando si modifica in
→ ref readonly
(se si richiama il puntatore con il modificatore del sito di chiamata in
), in linea con i metodi normali.
Modifiche interrompenti
Il ref
/in
relax non corrispondente nella risoluzione dell'overload introduce una modifica che causa un'interruzione del comportamento illustrata nell'esempio seguente:
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";
}
In C# 11 la chiamata viene associata a E.M
, quindi "E"
viene stampata.
In C# 12, C.M
è autorizzato a eseguire l'associazione (con un avviso) e non viene eseguita alcuna ricerca negli ambiti di estensione poiché è disponibile un candidato applicabile, pertanto "C"
viene stampato.
C'è anche una modifica del codice sorgente che causa un'interruzione per lo stesso motivo.
L'esempio seguente stampa "1"
in C# 11, ma non riesce a compilare con un errore di ambiguità in 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";
}
Gli esempi precedenti illustrano le interruzioni per le chiamate al metodo, ma poiché sono causate da modifiche alla risoluzione dell'overload, possono essere attivate in modo analogo per le conversioni dei metodi.
Alternative
dichiarazioni di parametri
Gli autori di API possono annotare in
parametri progettati per accettare solo lvalue con un attributo personalizzato e fornire un analizzatore per contrassegnare utilizzi non corretti.
Ciò non consente agli autori di API di modificare le firme delle API esistenti che hanno scelto di usare parametri ref
per impedire rvalue.
I chiamanti di tali API devono comunque eseguire operazioni aggiuntive per ottenere un ref
se hanno accesso solo a una variabile ref readonly
.
La modifica di queste API da ref
a [RequiresLocation] in
sarebbe una modifica che interrompe il codice sorgente (e, nel caso di metodi virtuali, anche un'interruzione binaria).
Invece di consentire il modificatore ref readonly
, il compilatore potrebbe riconoscere quando un attributo speciale (ad esempio [RequiresLocation]
) viene applicato a un parametro.
Questo argomento è stato illustrato in LDM 2022-04-25, decidendo che si tratta di una funzionalità del linguaggio, non di un analizzatore, quindi dovrebbe essere simile a una.
controllo tipo valore
Passare lvalue senza modificatori ai parametri ref readonly
può essere consentito senza avvisi, in modo analogo ai parametri byref impliciti di C++.
Questo argomento è stato discusso in LDM 2022-05-11, notando che la motivazione principale per i parametri ref readonly
sono API che acquisiscono o restituiscono riferimenti da questi parametri, quindi l'indicatore di qualche tipo è una buona cosa.
Il passaggio di rvalue a un ref readonly
potrebbe essere un errore, non un avviso.
Questo è stato inizialmente accettato in LDM 2022-04-25, ma le discussioni di posta elettronica successive hanno attenuato questa decisione poiché altrimenti si perderebbe la possibilità di modificare le API esistenti senza compromettere gli utenti.
in
potrebbe essere il modificatore di callsite "naturale" per i parametri ref readonly
e l'uso di ref
potrebbe generare avvisi.
In questo modo si garantisce uno stile di codice coerente e si rende evidente al punto di chiamata che il riferimento è readonly (a differenza di ref
).
Inizialmente è stato accettato in LDM 2022-04-25.
Tuttavia, gli avvisi potrebbero essere un punto di attrito per consentire agli autori di API di passare da ref
a ref readonly
.
Inoltre, in
è stato ridefinito come ref readonly
+ funzionalità di praticità, di conseguenza questo è stato rifiutato in LDM 2022-05-11.
Revisione LDM in sospeso
Nessuna delle opzioni seguenti è stata implementata in C# 12. Essi rimangono potenziali proposte.
dichiarazioni di parametri
È possibile consentire l'ordinamento inverso dei modificatori (readonly ref
anziché ref readonly
).
Ciò sarebbe incoerente con il modo in cui readonly ref
restituisce e i campi (l'ordinamento inverso non è consentito o significa rispettivamente qualcosa di diverso) e potrebbe scontrarsi con parametri di sola lettura se implementati in futuro.
I valori dei parametri predefiniti possono essere un errore per i parametri ref readonly
.
controlli del tipo di valore
È possibile generare errori anziché avvisi quando si passano rvalue a parametri ref readonly
o quando le annotazioni del sito di chiamata e i modificatori di parametri non corrispondono.
Analogamente, è possibile usare modreq
speciali anziché un attributo per garantire che i parametri ref readonly
siano distinti dai parametri in
a livello binario.
Ciò garantisce garanzie più solide, quindi sarebbe consigliabile per le nuove API, ma impedire l'adozione nelle API di runtime esistenti che non possono introdurre modifiche di rilievo.
I controlli dei tipi di valore possono essere rilassati per consentire il passaggio di riferimenti di sola lettura tramite ref
nei parametri in
/ref readonly
.
Questo sarebbe simile al funzionamento delle assegnazioni di riferimento e dei ritorni ref oggi; essi permettono anche il passaggio di riferimenti come readonly utilizzando il modificatore ref
sull'espressione di origine.
Tuttavia, il ref
si trova di solito vicino al punto in cui la destinazione viene dichiarata come ref readonly
, quindi è chiaro che stiamo passando un riferimento come sola lettura, a differenza delle invocazioni i cui modificatori di argomento e parametro di solito sono distanti.
Inoltre, consentono di solo modificatore ref
a differenza degli argomenti che consentono anche in
, di conseguenza in
e ref
sarebbero diventati intercambiabili per gli argomenti o in
sarebbero diventati praticamente obsoleti se gli utenti desiderassero rendere coerente il codice (probabilmente userebbero ref
ovunque poiché è l'unico modificatore consentito per le assegnazioni di riferimento e i ritorni di riferimento).
risoluzione del sovraccarico
La risoluzione dell'overload, l'override e la conversione potrebbero impedire l'interscambio tra i modificatori ref readonly
e in
.
La modifica della risoluzione dell'overload per i parametri di in
esistenti potrebbe essere presa in modo incondizionato (non considerando LangVersion), ma sarebbe una modifica che causa un'interruzione.
Il richiamo di un metodo di estensione con il ricevitore ref readonly
potrebbe generare un avviso: "L'argomento 1 deve essere passato con la parola chiave ref
o in
", come per le invocazioni non di estensione prive di modificatori (l'utente potrebbe correggere tale avviso trasformando l'invocazione del metodo di estensione in un'invocazione di metodo statico).
Lo stesso avviso potrebbe essere segnalato quando si usa l'inizializzatore di raccolta personalizzato o il gestore di stringhe interpolato con il parametro ref readonly
, anche se l'utente non poteva aggirarlo.
ref readonly
gli overloads potrebbero essere preferiti agli overloads per valore quando non è presente alcun modificatore di callsite o si potrebbe verificare un errore di ambiguità.
conversioni di metodi
È possibile consentire al parametro ref
del metodo di destinazione, in modo che corrisponda ai parametri in
e ref readonly
del delegato.
In questo modo gli autori di API possono modificare, ad esempio, ref
in in
nelle firme delegate senza interrompere gli utenti (in modo coerente con ciò che è consentito per le firme normali dei metodi).
Tuttavia, risulterebbe nella seguente violazione delle garanzie readonly
con soltanto un avvertimento:
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
}
}
Le conversioni dei puntatori a funzione potrebbero avvisare in caso di mancata corrispondenza ref readonly
/ref
/in
, ma per condizionarlo su LangVersion, sarebbe necessario un notevole investimento nell'implementazione, poiché attualmente le conversioni dei tipi non richiedono l'accesso alla compilazione.
Inoltre, anche se il disallineamento è attualmente un errore, è facile per gli utenti aggiungere un cast per accettare il disallineamento se lo desiderano.
codifica dei metadati
È possibile specificare il RequiresLocationAttribute
nell'origine, in modo analogo agli attributi In
e Out
.
In alternativa, potrebbe trattarsi di un errore quando applicato in altri contesti rispetto ai soli parametri, in modo analogo all'attributo IsReadOnly
; per preservare ulteriormente lo spazio di progettazione.
I parametri del puntatore di funzione ref readonly
possono essere generati con combinazioni di modopt
/modreq
diverse (si noti che "interruzione del codice sorgente" in questa tabella si riferisce ai chiamanti con LangVersion <= 11
):
Modificatori | Può essere riconosciuto tra compilazioni | I compilatori precedenti li vedono come |
ref → ref readonly |
in → ref readonly |
---|---|---|---|---|
modreq(In) modopt(RequiresLocation) |
Sì | in |
binario, interruzione del codice sorgente | interruzione binaria |
modreq(In) |
No | in |
binario, interruzione del codice sorgente | Ok |
modreq(RequiresLocation) |
Sì | non confermato | binario, interruzione del codice sorgente | binario, interruzione del sorgente |
modopt(RequiresLocation) |
Sì | ref |
interruzione binaria | binario, interruzione del codice sorgente |
È possibile generare attributi [RequiresLocation]
e [IsReadOnly]
per i parametri di ref readonly
.
Quindi in
→ ref readonly
non sarebbe una modifica significativa anche per le versioni precedenti del compilatore, ma ref
→ ref readonly
diventerebbe una modifica incompatibile con il codice sorgente per le versioni meno recenti del compilatore (poiché interpretano ref readonly
come in
, non consentendo i modificatori ref
) così come per le nuove versioni del compilatore con LangVersion <= 11
(per garantire coerenza).
È possibile rendere il comportamento per LangVersion <= 11
diverso dal comportamento per le versioni precedenti del compilatore.
Ad esempio, potrebbe trattarsi di un errore ogni volta che viene chiamato un parametro ref readonly
(anche quando si usa il modificatore ref
nel callite) o può essere sempre consentito senza errori.
Cambiamenti dirompenti
Questa proposta suggerisce di accettare una modifica che altera il comportamento perché è raro che si verifichi, è delimitata da LangVersion e gli utenti possono aggirarla chiamando il metodo di estensione in modo esplicito. Invece, potremmo attenuarlo
- Impedire la mancata corrispondenza tra
ref
/in
(che impedirebbe solo la migrazione ain
per le API precedenti che usavanoref
perchéin
non era ancora disponibile), - modifica delle regole di risoluzione del sovraccarico per continuare a cercare una corrispondenza migliore (determinata dalle regole di miglioramento specificate di seguito) quando si verifica una mancata corrispondenza del tipo ref introdotta in questa proposta,
- o in alternativa continuare solo per la mancata corrispondenza di
ref
vs.in
, non con gli altri (ref readonly
vs.ref
/in
/by-value).
- o in alternativa continuare solo per la mancata corrispondenza di
Regole di miglioramento
L'esempio seguente genera attualmente tre errori di ambiguità per le tre chiamate di M
.
È possibile aggiungere nuove regole di migliorezza per risolvere le ambiguità.
In questo modo si risolverà anche la modifica che causa un'interruzione di origine descritta in precedenza.
Un modo sarebbe quello di fare in modo che l'esempio stampi 221
(dove il parametro ref readonly
è abbinato all'argomento in
, poiché sarebbe un avviso chiamarlo senza modificatore, mentre per il parametro in
è consentito).
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));
}
}
Le nuove regole di miglioramento potrebbero contrassegnare come peggio il parametro il cui argomento potrebbe essere stato passato con un modificatore di argomento diverso per migliorarlo.
In altre parole, l'utente deve sempre essere in grado di trasformare un parametro peggiore in un parametro migliore modificando il modificatore di argomento corrispondente.
Ad esempio, quando un argomento viene passato da in
, un parametro ref readonly
è preferibile rispetto a un parametro in
perché l'utente potrebbe passare l'argomento per valore per scegliere il parametro in
.
Questa regola è solo un'estensione della regola di preferenza per valore/in
che è in vigore oggi (è l'ultima regola di risoluzione dell'overload e l'intero overload è migliore se uno dei relativi parametri è migliore e nessuno è peggiore del parametro corrispondente di un altro overload).
discussione | parametro migliore | parametro peggiore |
---|---|---|
ref /in |
ref readonly |
in |
ref |
ref |
ref readonly /in |
per valore | per valore/in |
ref readonly |
in |
in |
ref |
È consigliabile gestire le conversioni dei metodi in modo analogo.
L'esempio seguente genera attualmente due errori di ambiguità per le due assegnazioni di delegati.
Le nuove regole di preferenza potrebbero preferire un parametro del metodo il cui modificatore di riferimento corrisponda al modificatore di riferimento del parametro del delegato di destinazione corrispondente rispetto a uno che non corrisponde.
Di conseguenza, l'esempio seguente stampa 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);
Riunioni progettuali
- LDM 2022-04-25: funzionalità accettata
- LDM 2022-05-09: discussione suddivisa in tre parti
-
LDM 2022-05-11: consentito
ref
e nessuna annotazione callsite per i parametriref readonly
C# feature specifications