Riferimenti di sola letturaReadonly references

  • [x] proposto[x] Proposed
  • Prototipo [x][x] Prototype
  • Implementazione di [x]: avviata[x] Implementation: Started
  • [] Specifica: non avviata[ ] Specification: Not Started

RiepilogoSummary

La funzionalità "riferimenti di sola lettura" è in realtà un gruppo di funzionalità che sfruttano l'efficienza del passaggio di variabili in base al riferimento, ma senza esporre i dati alle modifiche:The "readonly references" feature is actually a group of features that leverage the efficiency of passing variables by reference, but without exposing the data to modifications:

  • in parametriin parameters
  • Valori restituiti ref readonlyref readonly returns
  • readonly strutturereadonly structs
  • ref/in metodi di estensioneref/in extension methods
  • ref readonly localiref readonly locals
  • ref espressioni condizionaliref conditional expressions

Passaggio di argomenti come riferimenti di sola lettura.Passing arguments as readonly references.

Esiste una proposta esistente che tocca questo argomento https://github.com/dotnet/roslyn/issues/115 come un caso speciale di parametri ReadOnly senza passare a molti dettagli.There is an existing proposal that touches this topic https://github.com/dotnet/roslyn/issues/115 as a special case of readonly parameters without going into many details. Qui voglio solo confermare che l'idea non è stata molto nuova.Here I just want to acknowledge that the idea by itself is not very new.

MotivazioneMotivation

Prima di questa funzionalità, in C# non era disponibile un modo efficiente per esprimere il desiderio di passare le variabili struct nelle chiamate al metodo per le operazioni di sola lettura senza alcuna modifica.Prior to this feature C# did not have an efficient way of expressing a desire to pass struct variables into method calls for readonly purposes with no intention of modifying. Il passaggio di un argomento per valore normale implica la copia, che aggiunge costi superflui.Regular by-value argument passing implies copying, which adds unnecessary costs. Che consente agli utenti di usare l'argomento per-Ref passando e si basano su Commenti/documentazione per indicare che i dati non devono essere mutati dal chiamato.That drives users to use by-ref argument passing and rely on comments/documentation to indicate that the data is not supposed to be mutated by the callee. Non è una soluzione ideale per molti motivi.It is not a good solution for many reasons.
Gli esempi sono gli operatori matematici di tipo Vector/Matrix nelle librerie grafiche, come XNA , che hanno operandi di riferimento esclusivamente a causa di considerazioni sulle prestazioni.The examples are numerous - vector/matrix math operators in graphics libraries like XNA are known to have ref operands purely because of performance considerations. Nel compilatore Roslyn è presente codice che usa gli struct per evitare allocazioni e quindi li passa per riferimento per evitare di copiare i costi.There is code in Roslyn compiler itself that uses structs to avoid allocations and then passes them by reference to avoid copying costs.

Soluzione ( in parametri)Solution (in parameters)

Analogamente ai out parametri, i in parametri vengono passati come riferimenti gestiti con garanzie aggiuntive da parte del chiamato.Similarly to the out parameters, in parameters are passed as managed references with additional guarantees from the callee.
A differenza dei out parametri che devono essere assegnati dal chiamato prima di qualsiasi altro uso, in i parametri non possono essere assegnati dal chiamato.Unlike out parameters which must be assigned by the callee before any other use, in parameters cannot be assigned by the callee at all.

Di conseguenza, in i parametri consentono l'efficacia del passaggio di argomenti indiretti senza esporre argomenti alle mutazioni da parte del chiamato.As a result in parameters allow for effectiveness of indirect argument passing without exposing arguments to mutations by the callee.

Dichiarazione di parametri inDeclaring in parameters

in i parametri vengono dichiarati utilizzando in la parola chiave come modificatore nella firma del parametro.in parameters are declared by using in keyword as a modifier in the parameter signature.

Per tutti gli scopi in , il parametro viene considerato come una readonly variabile.For all purposes the in parameter is treated as a readonly variable. La maggior parte delle restrizioni relative all'uso di in parametri all'interno del metodo è identica a quella dei readonly campi.Most of the restrictions on the use of in parameters inside the method are the same as with readonly fields.

Un in parametro può effettivamente rappresentare un readonly campo.Indeed an in parameter may represent a readonly field. La somiglianza delle restrizioni non è una coincidenza.Similarity of restrictions is not a coincidence.

Ad esempio, i campi di un in parametro con un tipo di struct sono tutti classificati in modo ricorsivo come readonly variabili.For example fields of an in parameter which has a struct type are all recursively classified as readonly variables .

static Vector3 Add (in Vector3 v1, in Vector3 v2)
{
    // not OK!!
    v1 = default(Vector3);

    // not OK!!
    v1.X = 0;

    // not OK!!
    foo(ref v1.X);

    // OK
    return new Vector3(v1.X + v2.X, v1.Y + v2.Y, v1.Z + v2.Z);
}
  • in i parametri sono consentiti ovunque, in cui sono consentiti parametri ByVal comuni.in parameters are allowed anywhere where ordinary byval parameters are allowed. Sono inclusi gli indicizzatori, gli operatori (incluse le conversioni), i delegati, le espressioni lambda, le funzioni locali.This includes indexers, operators (including conversions), delegates, lambdas, local functions.
 (in int x) => x                                                     // lambda expression  
 TValue this[in TKey index];                                         // indexer
 public static Vector3 operator +(in Vector3 x, in Vector3 y) => ... // operator
  • in non è consentita in combinazione con out o con qualsiasi elemento che non è out combinato con.in is not allowed in combination with out or with anything that out does not combine with.

  • Non è consentito eseguire l'overload delle ref / out / in differenze.It is not permitted to overload on ref/out/in differences.

  • È consentita l'overload per le differenze e il ByVal comune in .It is permitted to overload on ordinary byval and in differences.

  • Per lo scopo di OHI (overload, nascondere, implementazione), si in comporta in modo analogo a un out parametro.For the purpose of OHI (Overloading, Hiding, Implementing), in behaves similarly to an out parameter. Si applicano tutte le stesse regole.All the same rules apply. Ad esempio, il metodo che esegue l'override deve corrispondere ai in parametri con in parametri di un tipo convertibile di identità.For example the overriding method will have to match in parameters with in parameters of an identity-convertible type.

  • Per quanto riguarda le conversioni di gruppi delegato/Lambda/metodo, in si comporta in modo analogo a un out parametro.For the purpose of delegate/lambda/method group conversions, in behaves similarly to an out parameter. Le espressioni lambda e i candidati per la conversione dei gruppi di metodi applicabili dovranno corrispondere ai in parametri del delegato di destinazione con i in parametri di un tipo convertibile in identità.Lambdas and applicable method group conversion candidates will have to match in parameters of the target delegate with in parameters of an identity-convertible type.

  • Ai fini della varianza generica, i in parametri sono non variant.For the purpose of generic variance, in parameters are nonvariant.

Nota: non sono presenti avvisi per in parametri con tipi di riferimento o primitivi.NOTE: There are no warnings on in parameters that have reference or primitives types. Potrebbe essere inutile in generale, ma in alcuni casi l'utente deve/vuole passare le primitive come in .It may be pointless in general, but in some cases user must/want to pass primitives as in. Esempi: override di un metodo generico Method(in T param) T , ad esempio quando è stato sostituito int o quando si hanno metodi come Volatile.Read(in int location)Examples - overriding a generic method like Method(in T param) when T was substituted to be int, or when having methods like Volatile.Read(in int location)

È preferibile disporre di un analizzatore in grado di avvisare in caso di uso inefficiente di in parametri, ma le regole per tale analisi sarebbero troppo fuzzy per essere parte di una specifica del linguaggio.It is conceivable to have an analyzer that warns in cases of inefficient use of in parameters, but the rules for such analysis would be too fuzzy to be a part of a language specification.

Uso di in nei siti di chiamata.Use of in at call sites. ( in argomenti)(in arguments)

Esistono due modi per passare gli argomenti ai in parametri.There are two ways to pass arguments to in parameters.

in gli argomenti possono corrispondere a in parametri:in arguments can match in parameters:

Un argomento con un in modificatore nel sito di chiamata può corrispondere ai in parametri.An argument with an in modifier at the call site can match in parameters.

int x = 1;

void M1<T>(in T x)
{
  // . . .
}

var x = M1(in x);  // in argument to a method

class D
{
    public string this[in Guid index];
}

D dictionary = . . . ;
var y = dictionary[in Guid.Empty]; // in argument to an indexer
  • in l'argomento deve essere un lvalue leggibile (*).in argument must be a readable LValue(*). Esempio: M1(in 42) non è validoExample: M1(in 42) is invalid

(*) Il concetto di lvalue/rvalue varia tra le lingue.(*) The notion of LValue/RValue vary between languages.
Qui, da LValue, intendo un'espressione che rappresenta una posizione a cui è possibile fare riferimento direttamente.Here, by LValue I mean an expression that represent a location that can be referred to directly. E RValue indica un'espressione che produce un risultato temporaneo che non viene mantenuto autonomamente.And RValue means an expression that yields a temporary result which does not persist on its own.

  • In particolare readonly , è possibile passare campi, in parametri o altre variabili formalmente readonly come in argomenti.In particular it is valid to pass readonly fields, in parameters or other formally readonly variables as in arguments. Esempio: dictionary[in Guid.Empty] è valido.Example: dictionary[in Guid.Empty] is legal. Guid.Empty è un campo statico di sola lettura.Guid.Empty is a static readonly field.

  • in l'argomento deve avere l'identità del tipo convertibile nel tipo di parametro.in argument must have type identity-convertible to the type of the parameter. Esempio: M1<object>(in Guid.Empty) non è valido.Example: M1<object>(in Guid.Empty) is invalid. Guid.Emptynon è convertibile in identitàobjectGuid.Empty is not identity-convertible to object

La motivazione per le regole precedenti è che gli in argomenti garantiscono l' aliasing della variabile dell'argomento.The motivation for the above rules is that in arguments guarantee aliasing of the argument variable. Il chiamato riceve sempre un riferimento diretto alla stessa posizione rappresentata dall'argomento.The callee always receives a direct reference to the same location as represented by the argument.

  • in rari casi in cui gli in argomenti devono essere distribuiti nello stack a causa di await espressioni utilizzate come operandi della stessa chiamata, il comportamento è identico a quello out degli ref argomenti e. se la variabile non può essere distribuita in modo referenziale, viene restituito un errore.in rare situations when in arguments must be stack-spilled due to await expressions used as operands of the same call, the behavior is the same as with out and ref arguments - if the variable cannot be spilled in referentially-transparent manner, an error is reported.

Esempi:Examples:

  1. M1(in staticField, await SomethingAsync()) è valido.M1(in staticField, await SomethingAsync()) is valid. staticField è un campo statico a cui è possibile accedere più di una volta senza effetti collaterali osservabili.staticField is a static field which can be accessed more than once without observable side effects. È quindi possibile fornire sia l'ordine degli effetti collaterali che i requisiti di aliasing.Therefore both the order of side effects and aliasing requirements can be provided.
  2. M1(in RefReturningMethod(), await SomethingAsync()) verrà generato un errore.M1(in RefReturningMethod(), await SomethingAsync()) will produce an error. RefReturningMethod() è un ref metodo di restituzione.RefReturningMethod() is a ref returning method. Una chiamata al metodo può avere effetti collaterali osservabili, pertanto deve essere valutata prima dell' SomethingAsync() operando.A method call may have observable side effects, therefore it must be evaluated before the SomethingAsync() operand. Tuttavia, il risultato della chiamata è un riferimento che non può essere mantenuto nel await punto di sospensione che rende impossibile il requisito di riferimento diretto.However the result of the invocation is a reference that cannot be preserved across the await suspension point which make the direct reference requirement impossible.

Nota: gli errori di distribuzione dello stack sono considerati limitazioni specifiche dell'implementazione.NOTE: the stack spilling errors are considered to be implementation-specific limitations. Pertanto non hanno effetto sulla risoluzione dell'overload o sull'inferenza lambda.Therefore they do not have effect on overload resolution or lambda inference.

Gli argomenti ByVal comuni possono corrispondere ai in parametri:Ordinary byval arguments can match in parameters:

Gli argomenti regolari senza modificatori possono corrispondere a in parametri.Regular arguments without modifiers can match in parameters. In tal caso, gli argomenti hanno gli stessi vincoli rilassati di un normale argomento ByVal.In such case the arguments have the same relaxed constraints as an ordinary byval arguments would have.

La motivazione di questo scenario è che in i parametri nelle API possono comportare inconvenienti per l'utente quando gli argomenti non possono essere passati come riferimenti diretti, ad esempio valori letterali, risultati calcolati o await ed argomenti che hanno tipi più specifici.The motivation for this scenario is that in parameters in APIs may result in inconveniences for the user when arguments cannot be passed as a direct reference - ex: literals, computed or await-ed results or arguments that happen to have more specific types.
Tutti questi casi hanno una soluzione semplice per archiviare il valore dell'argomento in una lingua locale temporanea di tipo appropriato e passare tale oggetto locale come in argomento.All these cases have a trivial solution of storing the argument value in a temporary local of appropriate type and passing that local as an in argument.
Per ridurre la necessità del compilatore di codice standard, è possibile eseguire la stessa trasformazione, se necessario, quando in il modificatore non è presente nel sito di chiamata.To reduce the need for such boilerplate code compiler can perform the same transformation, if needed, when in modifier is not present at the call site.

Inoltre, in alcuni casi, ad esempio la chiamata di operatori o in i metodi di estensione, non esiste alcun modo sintattico di specificare in .In addition, in some cases, such as invocation of operators, or in extension methods, there is no syntactical way to specify in at all. Questo solo richiede la specifica del comportamento degli argomenti ByVal comuni quando corrispondono ai in parametri.That alone requires specifying the behavior of ordinary byval arguments when they match in parameters.

In particolare:In particular:

  • il passaggio di RValues è valido.it is valid to pass RValues. Un riferimento a un oggetto temporaneo viene passato in questo caso.A reference to a temporary is passed in such case. Esempio:Example:
Print("hello");      // not an error.

void Print<T>(in T x)
{
  //. . .
}
  • sono consentite conversioni implicite.implicit conversions are allowed.

Si tratta in realtà di un caso speciale di passaggio di un RValueThis is actually a special case of passing an RValue

In tal caso, viene passato un riferimento a un valore convertito temporaneo.A reference to a temporary holding converted value is passed in such case. Esempio:Example:

Print<int>(Short.MaxValue)     // not an error.
  • nel caso di un destinatario di un in metodo di estensione, anziché di metodi di ref estensione, sono consentite le conversioni di RValues o implicite.in a case of a receiver of an in extension method (as opposed to ref extension methods), RValues or implicit this-argument-conversions are allowed. In tal caso, viene passato un riferimento a un valore convertito temporaneo.A reference to a temporary holding converted value is passed in such case. Esempio:Example:
public static IEnumerable<T> Concat<T>(in this (IEnumerable<T>, IEnumerable<T>) arg)  => . . .;

("aa", "bb").Concat<char>()    // not an error.

Ulteriori informazioni sui ref / in metodi di estensione sono fornite più avanti in questo documento.More information on ref/in extension methods is provided further in this document.

  • la distribuzione degli argomenti dovuta agli await operandi potrebbe essere "per valore", se necessario.argument spilling due to await operands could spill "by-value", if necessary. Negli scenari in cui non è possibile fornire un riferimento diretto all'argomento a causa della presenza di await una copia del valore dell'argomento viene invece distribuito.In scenarios where providing a direct reference to the argument is not possible due to intervening await a copy of the argument's value is spilled instead.
    Esempio:Example:
M1(RefReturningMethod(), await SomethingAsync())   // not an error.

Poiché il risultato di una chiamata di effetto collaterale è un riferimento che non può essere mantenuto attraverso await la sospensione, viene invece mantenuto un oggetto temporaneo che contiene il valore effettivo (come in un caso di parametro ByVal comune).Since the result of a side-effecting invocation is a reference that cannot be preserved across await suspension, a temporary containing the actual value will be preserved instead (as it would in an ordinary byval parameter case).

Argomenti facoltativi omessiOmitted optional arguments

È consentito che un in parametro specifichi un valore predefinito.It is permitted for an in parameter to specify a default value. Che rende facoltativo l'argomento corrispondente.That makes the corresponding argument optional.

Se si omette l'argomento facoltativo nel sito di chiamata, il valore predefinito viene passato tramite un oggetto temporaneo.Omitting optional argument at the call site results in passing the default value via a temporary.

Print("hello");      // not an error, same as
Print("hello", c: Color.Black);

void Print(string s, in Color c = Color.Black)
{
    // . . .
}

Comportamento degli alias in generaleAliasing behavior in general

Analogamente ref out alle variabili e, le in variabili sono riferimenti/alias a percorsi esistenti.Just like ref and out variables, in variables are references/aliases to existing locations.

Sebbene il chiamato non sia autorizzato a scrivere in essi, la lettura in di un parametro può osservare valori diversi come effetto collaterale di altre valutazioni.While callee is not allowed to write into them, reading an in parameter can observe different values as a side effect of other evaluations.

Esempio:Example:

static Vector3 v = Vector3.UnitY;

static void Main()
{
    Test(v);
}

static void Test(in Vector3 v1)
{
    Debug.Assert(v1 == Vector3.UnitY);
    // changes v1 deterministically (no races required)
    ChangeV();
    Debug.Assert(v1 == Vector3.UnitX);
}

static void ChangeV()
{
    v = Vector3.UnitX;
}

in parametri e acquisizione di variabili locali.in parameters and capturing of local variables.

Ai fini del comportamento dei parametri di acquisizione lambda/Async si in comporta come i out ref parametri e.For the purpose of lambda/async capturing in parameters behave the same as out and ref parameters.

  • in Impossibile acquisire parametri in una chiusurain parameters cannot be captured in a closure
  • in i parametri non sono consentiti nei metodi iteratorin parameters are not allowed in iterator methods
  • in i parametri non sono consentiti nei metodi asincroniin parameters are not allowed in async methods

Variabili temporanee.Temporary variables.

Alcuni usi del in passaggio dei parametri possono richiedere l'uso indiretto di una variabile locale temporanea:Some uses of in parameter passing may require indirect use of a temporary local variable:

  • in gli argomenti vengono sempre passati come alias diretti quando il sito di chiamata utilizza in .in arguments are always passed as direct aliases when call-site uses in. Il tipo temporaneo non viene mai usato in questo caso.Temporary is never used in such case.
  • in non è necessario che gli argomenti siano alias diretti quando il sito di chiamata non utilizza in .in arguments are not required to be direct aliases when call-site does not use in. Quando argument non è un LValue, è possibile usare un oggetto temporaneo.When argument is not an LValue, a temporary may be used.
  • in il parametro può avere un valore predefinito.in parameter may have default value. Quando l'argomento corrispondente viene omesso nel sito di chiamata, il valore predefinito viene passato tramite un oggetto temporaneo.When corresponding argument is omitted at the call site, the default value are passed via a temporary.
  • in gli argomenti possono includere conversioni implicite, incluse quelle che non conservano l'identità.in arguments may have implicit conversions, including those that do not preserve identity. In questi casi viene usato un oggetto temporaneo.A temporary is used in those cases.
  • i ricevitori di chiamate struct ordinarie non possono essere scrivibili lvalue (case esistente!).receivers of ordinary struct calls may not be writeable LValues (existing case!). In questi casi viene usato un oggetto temporaneo.A temporary is used in those cases.

Il tempo di vita dell'argomento temporaries corrisponde all'ambito più vicino a quello del sito di chiamata.The life time of the argument temporaries matches the closest encompassing scope of the call-site.

Il tempo di vita formale delle variabili temporanee è semanticamente significativo in scenari che coinvolgono l'analisi di escape delle variabili restituite per riferimento.The formal life time of temporary variables is semantically significant in scenarios involving escape analysis of variables returned by reference.

Rappresentazione dei metadati dei in parametri.Metadata representation of in parameters.

Quando System.Runtime.CompilerServices.IsReadOnlyAttribute viene applicato a un parametro ByRef, significa che il parametro è un in parametro.When System.Runtime.CompilerServices.IsReadOnlyAttribute is applied to a byref parameter, it means that the parameter is an in parameter.

Inoltre, se il metodo è astratto o virtuale, la firma di tali parametri (e solo tali parametri) deve avere modreq[System.Runtime.InteropServices.InAttribute] .In addition, if the method is abstract or virtual, then the signature of such parameters (and only such parameters) must have modreq[System.Runtime.InteropServices.InAttribute].

Motivazione: questa operazione viene eseguita per garantire che in caso di override di metodo/implementazione dei in parametri corrispondano.Motivation: this is done to ensure that in a case of method overriding/implementing the in parameters match.

Gli stessi requisiti si applicano ai Invoke metodi nei delegati.Same requirements apply to Invoke methods in delegates.

Motivazione: ciò consente di garantire che i compilatori esistenti non possano semplicemente ignorare readonly quando si creano o assegnano delegati.Motivation: this is to ensure that existing compilers cannot simply ignore readonly when creating or assigning delegates.

Restituzione per riferimento di sola lettura.Returning by readonly reference.

MotivazioneMotivation

La motivazione di questa funzionalità secondaria è approssimativamente simmetrica rispetto ai motivi per i in parametri, evitando la copia, ma sul lato di ritorno.The motivation for this sub-feature is roughly symmetrical to the reasons for the in parameters - avoiding copying, but on the returning side. Prima di questa funzionalità, un metodo o un indicizzatore aveva due opzioni: 1) restituito per riferimento ed essere esposto a possibili mutazioni o 2) restituito per valore che comporta la copia.Prior to this feature, a method or an indexer had two options: 1) return by reference and be exposed to possible mutations or 2) return by value which results in copying.

Soluzione ( ref readonly restituisce)Solution (ref readonly returns)

La funzionalità consente a un membro di restituire le variabili in base al riferimento senza esporle alle mutazioni.The feature allows a member to return variables by reference without exposing them to mutations.

Dichiarazione dei ref readonly membri restituzioneDeclaring ref readonly returning members

Una combinazione di modificatori ref readonly sulla firma restituita viene utilizzata per indicare che il membro restituisce un riferimento di sola lettura.A combination of modifiers ref readonly on the return signature is used to to indicate that the member returns a readonly reference.

Per tutti gli scopi, un ref readonly membro viene considerato come una readonly variabile, simile a readonly campi e in parametri.For all purposes a ref readonly member is treated as a readonly variable - similar to readonly fields and in parameters.

Ad esempio ref readonly , i campi di un membro che dispone di un tipo di struct sono tutti classificati in modo ricorsivo come readonly variabili.For example fields of ref readonly member which has a struct type are all recursively classified as readonly variables. -È consentito passarli come in argomenti, ma non come ref out argomenti o.- It is permitted to pass them as in arguments, but not as ref or out arguments.

ref readonly Guid Method1()
{
}

Method2(in Method1()); // valid. Can pass as `in` argument.

Method3(ref Method1()); // not valid. Cannot pass as `ref` argument
  • ref readonly i ritorni sono consentiti nelle stesse posizioni ref .ref readonly returns are allowed in the same places were ref returns are allowed. Sono inclusi gli indicizzatori, i delegati, le espressioni lambda, le funzioni locali.This includes indexers, delegates, lambdas, local functions.

  • Non è consentito eseguire l'overload in ref / ref readonly /delle differenze.It is not permitted to overload on ref/ref readonly / differences.

  • È consentita l'overload di per le differenze normali di ByVal e ref readonly return.It is permitted to overload on ordinary byval and ref readonly return differences.

  • Ai fini di OHI (overload, occultamento, implementazione), ref readonly è simile ma distinto da ref .For the purpose of OHI (Overloading, Hiding, Implementing), ref readonly is similar but distinct from ref. Ad esempio, un metodo che esegue l'override di ref readonly uno, deve essere ed essere di ref readonly tipo convertibile in identità.For example the a method that overrides ref readonly one, must itself be ref readonly and have identity-convertible type.

  • Per quanto riguarda le conversioni delegate/lambda/dei gruppi di metodi, ref readonly è simile ma distinto da ref .For the purpose of delegate/lambda/method group conversions, ref readonly is similar but distinct from ref. Le espressioni lambda e i candidati per la conversione di gruppi di metodi applicabili devono corrispondere alla ref readonly restituzione del delegato di destinazione con ref readonly la restituzione del tipo che è convertibile in identità.Lambdas and applicable method group conversion candidates have to match ref readonly return of the target delegate with ref readonly return of the type that is identity-convertible.

  • Ai fini della varianza generica, ref readonly i ritorni sono non variant.For the purpose of generic variance, ref readonly returns are nonvariant.

Nota: non sono presenti avvisi sui ref readonly ritorni con tipi di riferimento o primitivi.NOTE: There are no warnings on ref readonly returns that have reference or primitives types. Potrebbe essere inutile in generale, ma in alcuni casi l'utente deve/vuole passare le primitive come in .It may be pointless in general, but in some cases user must/want to pass primitives as in. Esempi: override di un metodo generico, ref readonly T Method() ad esempio quando T è stato sostituito con int .Examples - overriding a generic method like ref readonly T Method() when T was substituted to be int.

È preferibile disporre di un analizzatore in grado di avvisare in caso di utilizzo non efficiente dei ref readonly ritorni, ma le regole per tale analisi sarebbero troppo fuzzy per essere parte di una specifica del linguaggio.It is conceivable to have an analyzer that warns in cases of inefficient use of ref readonly returns, but the rules for such analysis would be too fuzzy to be a part of a language specification.

Restituzione da ref readonly membriReturning from ref readonly members

All'interno del corpo del metodo la sintassi è identica a quella dei normali ritorni Ref.Inside the method body the syntax is the same as with regular ref returns. L'oggetto readonly verrà dedotto dal metodo contenitore.The readonly will be inferred from the containing method.

La motivazione è che non return ref readonly <expression> è necessario molto tempo e consente solo la mancata corrispondenza della readonly parte che provocherebbe sempre errori.The motivation is that return ref readonly <expression> is unnecessary long and only allows for mismatches on the readonly part that would always result in errors. refÈ tuttavia necessario per garantire la coerenza con altri scenari in cui un elemento viene passato tramite un alias rigoroso rispetto al valore.The ref is, however, required for consistency with other scenarios where something is passed via strict aliasing vs. by value.

A differenza del case con i in parametri, ref readonly non restituisce mai alcun risultato tramite una copia locale.Unlike the case with in parameters, ref readonly returns never return via a local copy. Considerato che la copia smetterebbe di esistere immediatamente dopo la restituzione di tale procedura sarebbe inutile e pericolosa.Considering that the copy would cease to exist immediately upon returning such practice would be pointless and dangerous. Pertanto ref readonly , i restituzione sono sempre riferimenti diretti.Therefore ref readonly returns are always direct references.

Esempio:Example:

struct ImmutableArray<T>
{
    private readonly T[] array;

    public ref readonly T ItemRef(int i)
    {
        // returning a readonly reference to an array element
        return ref this.array[i];
    }
}

  • Un argomento di return ref deve essere un lvalue (regola esistente)An argument of return ref must be an LValue (existing rule)
  • Un argomento di return ref deve essere "safe to return" (regola esistente)An argument of return ref must be "safe to return" (existing rule)
  • In un ref readonly membro un argomento di return ref non deve essere scrivibile .In a ref readonly member an argument of return ref is not required to be writeable . Ad esempio, un membro può restituire Ref, un campo ReadOnly o uno dei relativi in parametri.For example such member can ref-return a readonly field or one of its in parameters.

Regole sicure per la restituzione.Safe to Return rules.

Le normali regole sicure per la restituzione dei riferimenti verranno applicate anche ai riferimenti di sola lettura.Normal safe to return rules for references will apply to readonly references as well.

Si noti che un oggetto ref readonly può essere ottenuto da un normale valore ref locale/parametro/restituito, ma non viceversa.Note that a ref readonly can be obtained from a regular ref local/parameter/return, but not the other way around. In caso contrario, la sicurezza dei ref readonly ritorni viene dedotta allo stesso modo dei normali ref ritorni.Otherwise the safety of ref readonly returns is inferred the same way as for regular ref returns.

Considerando che RValues può essere passato come in parametro e restituito perché è ref readonly necessaria una sola regola: RValues non sono sicuri per il ritorno per riferimento.Considering that RValues can be passed as in parameter and returned as ref readonly we need one more rule - RValues are not safe-to-return by reference.

Si consideri la situazione in cui un RValue viene passato a un in parametro tramite una copia e quindi restituito sotto forma di un oggetto ref readonly .Consider the situation when an RValue is passed to an in parameter via a copy and then returned back in a form of a ref readonly. Nel contesto del chiamante il risultato di tale chiamata è un riferimento ai dati locali e, di conseguenza, non è sicuro restituire.In the context of the caller the result of such invocation is a reference to local data and as such is unsafe to return. Una volta che RValues non è sicuro da restituire, la regola esistente #6 gestisce già questo caso.Once RValues are not safe to return, the existing rule #6 already handles this case.

Esempio:Example:

ref readonly Vector3 Test1()
{
    // can pass an RValue as "in" (via a temp copy)
    // but the result is not safe to return
    // because the RValue argument was not safe to return by reference
    return ref Test2(default(Vector3));
}

ref readonly Vector3 Test2(in Vector3 r)
{
    // this is ok, r is returnable
    return ref r;
}

safe to returnRegole aggiornate:Updated safe to return rules:

  1. i riferimenti alle variabili nell'heap possono essere restituiti in modo sicurorefs to variables on the heap are safe to return
  2. i parametri ref/in possono essere restituiti in in modo sicuro i parametri possono essere restituiti in modo naturale solo come ReadOnly.ref/in parameters are safe to return in parameters naturally can only be returned as readonly.
  3. i parametri out possono essere restituiti in modo sicuro , ma è necessario assegnarli definitivamente, come già nel caso attualeout parameters are safe to return (but must be definitely assigned, as is already the case today)
  4. i campi struct dell'istanza possono essere restituiti in modo sicuro finché il ricevitore è sicuro per la restituzioneinstance struct fields are safe to return as long as the receiver is safe to return
  5. ' This ' non è sicuro per restituire i membri struct'this' is not safe to return from struct members
  6. un riferimento, restituito da un altro metodo, può essere restituito in modo sicuro se tutti i refs/outs passati al metodo come parametri formali erano sicuri da restituire. In particolare, è irrilevante se il ricevitore è sicuro da restituire, indipendentemente dal fatto che il ricevitore sia uno struct, una classe o tipizzato come parametro di tipo generico.a ref, returned from another method is safe to return if all refs/outs passed to that method as formal parameters were safe to return. Specifically it is irrelevant if receiver is safe to return, regardless whether receiver is a struct, class or typed as a generic type parameter.
  7. RValues non è sicuro restituire per riferimento. In particolare, RValues è sicuro passare come parametri in.RValues are not safe to return by reference. Specifically RValues are safe to pass as in parameters.

Nota: esistono regole aggiuntive relative alla sicurezza dei ritorni che entrano in gioco quando sono interessati tipi di riferimento e riassegnazioni Ref.NOTE: There are additional rules regarding safety of returns that come into play when ref-like types and ref-reassignments are involved. Le regole si applicano ugualmente ai ref ref readonly membri e e pertanto non sono indicate in questo argomento.The rules equally apply to ref and ref readonly members and therefore are not mentioned here.

Comportamento degli alias.Aliasing behavior.

ref readonly i membri forniscono lo stesso comportamento di alias dei ref membri comuni (ad eccezione di ReadOnly).ref readonly members provide the same aliasing behavior as ordinary ref members (except for being readonly). Per questo motivo, per l'acquisizione di espressioni lambda, async, iteratori, distribuzione dello stack e così via... si applicano le stesse restrizioni.Therefore for the purpose of capturing in lambdas, async, iterators, stack spilling etc... the same restrictions apply. cioè.- I.E. a causa dell'impossibilità di acquisire i riferimenti effettivi e la natura degli effetti collaterali della valutazione dei membri, tali scenari non sono consentiti.due to inability to capture the actual references and due to side-effecting nature of member evaluation such scenarios are disallowed.

È consentita e necessaria per creare una copia quando ref readonly return è un destinatario di metodi struct normali, che accettano this come un riferimento scrivibile comune.It is permitted and required to make a copy when ref readonly return is a receiver of regular struct methods, which take this as an ordinary writeable reference. Storicamente, in tutti i casi in cui tali chiamate vengono applicate alla variabile ReadOnly, viene eseguita una copia locale.Historically in all cases where such invocations are applied to readonly variable a local copy is made.

Rappresentazione dei metadati.Metadata representation.

Quando System.Runtime.CompilerServices.IsReadOnlyAttribute viene applicato alla restituzione di un metodo di restituzione ByRef, significa che il metodo restituisce un riferimento di sola lettura.When System.Runtime.CompilerServices.IsReadOnlyAttribute is applied to the return of a byref returning method, it means that the method returns a readonly reference.

Inoltre, la firma del risultato di tali metodi (e solo quei metodi) deve avere modreq[System.Runtime.CompilerServices.IsReadOnlyAttribute] .In addition, the result signature of such methods (and only those methods) must have modreq[System.Runtime.CompilerServices.IsReadOnlyAttribute].

Motivazione: ciò consente di garantire che i compilatori esistenti non possano semplicemente ignorare readonly quando si richiamano metodi con i metodi ref readonly restituitiMotivation: this is to ensure that existing compilers cannot simply ignore readonly when invoking methods with ref readonly returns

Struct di sola letturaReadonly structs

In breve, funzionalità che rende il this parametro di tutti i membri di istanza di uno struct, tranne che per i costruttori, un in parametro.In short - a feature that makes this parameter of all instance members of a struct, except for constructors, an in parameter.

MotivazioneMotivation

Il compilatore deve presupporre che qualsiasi chiamata al metodo su un'istanza struct possa modificare l'istanza.Compiler must assume that any method call on a struct instance may modify the instance. In realtà, un riferimento scrivibile viene passato al metodo come this parametro e Abilita completamente questo comportamento.Indeed a writeable reference is passed to the method as this parameter and fully enables this behavior. Per consentire tali chiamate sulle readonly variabili, le chiamate vengono applicate alle copie temporanee.To allow such invocations on readonly variables, the invocations are applied to temp copies. Questo potrebbe essere poco intuitivo e talvolta impone agli utenti di abbandonarsi readonly per motivi di prestazioni.That could be unintuitive and sometimes forces people to abandon readonly for performance reasons.
Esempio: https://codeblog.jonskeet.uk/2014/07/16/micro-optimization-the-surprising-inefficiency-of-readonly-fields/Example: https://codeblog.jonskeet.uk/2014/07/16/micro-optimization-the-surprising-inefficiency-of-readonly-fields/

Dopo l'aggiunta del supporto per in i parametri e ref readonly la restituzione del problema della copia difensiva, le variabili di sola lettura diventeranno più comuni.After adding support for in parameters and ref readonly returns the problem of defensive copying will get worse since readonly variables will become more common.

SoluzioneSolution

Consentire readonly il modificatore nelle dichiarazioni di struct che comporterebbe il this trattamento come in parametro in tutti i metodi di istanza struct ad eccezione dei costruttori.Allow readonly modifier on struct declarations which would result in this being treated as in parameter on all struct instance methods except for constructors.

static void Test(in Vector3 v1)
{
    // no need to make a copy of v1 since Vector3 is a readonly struct
    System.Console.WriteLine(v1.ToString());
}

readonly struct Vector3
{
    . . .

    public override string ToString()
    {
        // not OK!!  `this` is an `in` parameter
        foo(ref this.X);

        // OK
        return $"X: {X}, Y: {Y}, Z: {Z}";
    }
}

Restrizioni sui membri dello struct di sola letturaRestrictions on members of readonly struct

  • I campi di istanza di uno struct di sola lettura devono essere di sola lettura.Instance fields of a readonly struct must be readonly.
    Motivazione: è possibile scrivere solo all'esterno, ma non tramite i membri.Motivation: can only be written to externally, but not through members.
  • Le proprietà autoproprietà dell'istanza di uno struct di sola lettura devono essere solo Get.Instance autoproperties of a readonly struct must be get-only.
    Motivazione: conseguenza della restrizione sui campi di istanza.Motivation: consequence of restriction on instance fields.
  • Lo struct di sola lettura non può dichiarare eventi simili a campi.Readonly struct may not declare field-like events.
    Motivazione: conseguenza della restrizione sui campi di istanza.Motivation: consequence of restriction on instance fields.

Rappresentazione dei metadati.Metadata representation.

Quando System.Runtime.CompilerServices.IsReadOnlyAttribute viene applicato a un tipo di valore, significa che il tipo è readonly struct .When System.Runtime.CompilerServices.IsReadOnlyAttribute is applied to a value type, it means that the type is a readonly struct.

In particolare:In particular:

  • L'identità del IsReadOnlyAttribute tipo non è importante.The identity of the IsReadOnlyAttribute type is unimportant. Infatti, se necessario, può essere incorporato dal compilatore nell'assembly contenitore.In fact it can be embedded by the compiler in the containing assembly if needed.

ref/in metodi di estensioneref/in extension methods

Esiste effettivamente una proposta esistente (e la richiesta pull https://github.com/dotnet/roslyn/issues/165) corrispondente del prototipo ( https://github.com/dotnet/roslyn/pull/15650) .There is actually an existing proposal (https://github.com/dotnet/roslyn/issues/165) and corresponding prototype PR (https://github.com/dotnet/roslyn/pull/15650). Voglio solo confermare che questa idea non è completamente nuova.I just want to acknowledge that this idea is not entirely new. È, tuttavia, pertinente in questo caso, ref readonly in quanto consente di rimuovere in modo elegante il problema più contenzioso relativo a tali metodi, ovvero cosa fare con i ricevitori rvalue.It is, however, relevant here since ref readonly elegantly removes the most contentious issue about such methods - what to do with RValue receivers.

L'idea generale è consentire ai metodi di estensione di prendere il this parametro per riferimento, purché il tipo sia noto come tipo di struct.The general idea is allowing extension methods to take the this parameter by reference, as long as the type is known to be a struct type.

public static void Extension(ref this Guid self)
{
    // do something
}

I motivi per la scrittura di tali metodi di estensione sono principalmente:The reasons for writing such extension methods are primarily:

  1. Evitare la copia quando Receiver è uno struct di grandi dimensioniAvoid copying when receiver is a large struct
  2. Consenti la mutazione di metodi di estensione su structAllow mutating extension methods on structs

I motivi per cui non si vuole consentire questa impostazione sulle classiThe reasons why we do not want to allow this on classes

  1. Lo scopo è molto limitato.It would be of very limited purpose.
  2. In questo modo si interrompe un'invariante che una chiamata al metodo non può trasformare il null ricevitore non ricevente dopo la chiamata null .It would break long standing invariant that a method call cannot turn non-null receiver to become null after invocation.

Infatti, attualmente una null variabile non può diventare, a null meno che non venga assegnata o passata in modo esplicito da ref o out .In fact, currently a non-null variable cannot become null unless explicitly assigned or passed by ref or out. Che facilita significativamente la leggibilità o altre forme di analisi "può essere un valore null".That greatly aids readability or other forms of "can this be a null here" analysis. 3. Sarebbe difficile riconciliare con la semantica "Evaluate once" degli accessi condizionali null.It would be hard to reconcile with "evaluate once" semantics of null-conditional accesses. Esempio: obj.stringField?.RefExtension(...) -è necessario acquisire una copia di stringField per rendere il controllo null significativo, ma le assegnazioni all' this interno di RefExtension non verranno riflesse nel campo.Example: obj.stringField?.RefExtension(...) - need to capture a copy of stringField to make the null check meaningful, but then assignments to this inside RefExtension would not be reflected back to the field.

La possibilità di dichiarare metodi di estensione su struct che accettano il primo argomento per riferimento è una richiesta di lunga durata.An ability to declare extension methods on structs that take the first argument by reference was a long-standing request. Una delle considerazioni di blocco è stata "cosa accade se il ricevitore non è un LValue?".One of the blocking consideration was "what happens if receiver is not an LValue?".

  • C'è un precedente che qualsiasi metodo di estensione può essere chiamato anche come metodo statico (a volte è l'unico modo per risolvere l'ambiguità).There is a precedent that any extension method could also be called as a static method (sometimes it is the only way to resolve ambiguity). Si impone che i ricevitori RValue non siano consentiti.It would dictate that RValue receivers should be disallowed.
  • D'altra parte, è necessario eseguire una chiamata in una copia in situazioni simili quando sono interessati i metodi di istanza struct.On the other hand there is a practice of making invocation on a copy in similar situations when struct instance methods are involved.

Il motivo per cui esiste la "copia implicita" è dato dal fatto che la maggior parte dei metodi struct non modifica effettivamente lo struct e non è in grado di indicare.The reason why the "implicit copying" exists is because the majority of struct methods do not actually modify the struct while not being able to indicate that. Quindi, la soluzione più pratica consisteva nel creare solo la chiamata a una copia, ma questa procedura è nota per danneggiare le prestazioni e causare bug.Therefore the most practical solution was to just make the invocation on a copy, but this practice is known for harming performance and causing bugs.

A questo punto, con in la disponibilità dei parametri, un'estensione può segnalare l'intento.Now, with availability of in parameters, it is possible for an extension to signal the intent. Di conseguenza, l'enigma può essere risolto richiedendo la ref chiamata di estensioni con ricevitori scrivibile mentre le in estensioni consentono la copia implicita, se necessario.Therefore the conundrum can be resolved by requiring ref extensions to be called with writeable receivers while in extensions permit implicit copying if necessary.

// this can be called on either RValue or an LValue
public static void Reader(in this Guid self)
{
    // do something nonmutating.
    WriteLine(self == default(Guid));
}

// this can be called only on an LValue
public static void Mutator(ref this Guid self)
{
    // can mutate self
    self = new Guid();
}

in estensioni e generics.in extensions and generics.

Lo scopo dei ref metodi di estensione è quello di modificare direttamente il ricevitore o richiamando membri mutanti.The purpose of ref extension methods is to mutate the receiver directly or by invoking mutating members. Le ref this T estensioni sono pertanto consentite purché T sia vincolato a essere uno struct.Therefore ref this T extensions are allowed as long as T is constrained to be a struct.

inPer ridurre la copia implicita, è possibile che esistano metodi di estensione specifici.On the other hand in extension methods exist specifically to reduce implicit copying. Tuttavia, l'utilizzo di un in T parametro dovrà essere eseguito tramite un membro di interfaccia.However any use of an in T parameter will have to be done through an interface member. Poiché tutti i membri di interfaccia sono considerati mutanti, qualsiasi utilizzo di questo tipo richiederebbe una copia.Since all interface members are considered mutating, any such use would require a copy. -Anziché ridurre la copia, l'effetto sarebbe l'opposto.- Instead of reducing copying, the effect would be the opposite. Pertanto in this T non è consentito quando T è un parametro di tipo generico indipendentemente dai vincoli.Therefore in this T is not allowed when T is a generic type parameter regardless of constraints.

Tipi validi di metodi di estensione (riepilogo):Valid kinds of extension methods (recap):

thisSono ora consentite le forme di dichiarazione seguenti in un metodo di estensione:The following forms of this declaration in an extension method are now allowed:

  1. this T arg : estensione ByVal normale.this T arg - regular byval extension. (caso esistente)(existing case)
  • T può essere qualsiasi tipo, inclusi i tipi di riferimento o parametri di tipo.T can be any type, including reference types or type parameters. L'istanza sarà la stessa variabile dopo la chiamata.Instance will be the same variable after the call. Consente le conversioni implicite di questo tipo di conversione di argomenti .Allows implicit conversions of this-argument-conversion kind. Può essere chiamato su RValues.Can be called on RValues.

  • in this T self - in estensione.in this T self - in extension. T deve essere un tipo struct effettivo.T must be an actual struct type. L'istanza sarà la stessa variabile dopo la chiamata.Instance will be the same variable after the call. Consente le conversioni implicite di questo tipo di conversione di argomenti .Allows implicit conversions of this-argument-conversion kind. Può essere chiamato su RValues (può essere richiamato su Temp se necessario).Can be called on RValues (may be invoked on a temp if needed).

  • ref this T self - ref estensione.ref this T self - ref extension. T deve essere un tipo struct o un parametro di tipo generico vincolato per essere uno struct.T must be a struct type or a generic type parameter constrained to be a struct. L'istanza può essere scritta dalla chiamata.Instance may be written to by the invocation. Consente solo le conversioni di identità.Allows only identity conversions. Deve essere chiamato su LValue scrivibile.Must be called on writeable LValue. (mai richiamato tramite una temperatura temporanea).(never invoked via a temp).

Variabili locali Ref di sola lettura.Readonly ref locals.

Motivazione.Motivation.

Una volta ref readonly introdotti i membri, è stato chiaro che è necessario associarli al tipo di locale appropriato.Once ref readonly members were introduced, it was clear from the use that they need to be paired with appropriate kind of local. La valutazione di un membro può produrre o osservare gli effetti collaterali, pertanto se il risultato deve essere usato più di una volta, deve essere archiviato.Evaluation of a member may produce or observe side effects, therefore if the result must be used more than once, it needs to be stored. Le normali ref variabili locali non sono utili perché non è possibile assegnarle un readonly riferimento.Ordinary ref locals do not help here since they cannot be assigned a readonly reference.

Soluzione.Solution.

Consente la dichiarazione di ref readonly variabili locali.Allow declaring ref readonly locals. Si tratta di un nuovo tipo di ref variabili locali non scrivibile.This is a new kind of ref locals that is not writeable. Di conseguenza, ref readonly le variabili locali possono accettare riferimenti a variabili di sola lettura senza esporre tali variabili alle Scritture.As a result ref readonly locals can accept references to readonly variables without exposing these variables to writes.

Dichiarazione e utilizzo di ref readonly variabili locali.Declaring and using ref readonly locals.

La sintassi di tali variabili locali utilizza i ref readonly modificatori nel sito di dichiarazione (nell'ordine specifico).The syntax of such locals uses ref readonly modifiers at declaration site (in that specific order). In modo analogo alle ref variabili locali normali, le ref readonly variabili locali devono essere inizializzate come ref alla dichiarazione.Similarly to ordinary ref locals, ref readonly locals must be ref-initialized at declaration. Diversamente dalle normali ref variabili locali, le ref readonly variabili locali possono fare riferimento a readonly lvalue come in parametri, readonly campi e ref readonly metodi.Unlike regular ref locals, ref readonly locals can refer to readonly LValues like in parameters, readonly fields, ref readonly methods.

Per tutti gli scopi ref readonly , un oggetto locale viene considerato come una readonly variabile.For all purposes a ref readonly local is treated as a readonly variable. La maggior parte delle restrizioni relative all'utilizzo è identica a quella dei readonly campi o dei in parametri.Most of the restrictions on the use are the same as with readonly fields or in parameters.

Ad esempio, i campi di un in parametro con un tipo di struct sono tutti classificati in modo ricorsivo come readonly variabili.For example fields of an in parameter which has a struct type are all recursively classified as readonly variables .

static readonly ref Vector3 M1() => . . .

static readonly ref Vector3 M1_Trace()
{
    // OK
    ref readonly var r1 = ref M1();

    // Not valid. Need an LValue
    ref readonly Vector3 r2 = ref default(Vector3);

    // Not valid. r1 is readonly.
    Mutate(ref r1);

    // OK.
    Print(in r1);

    // OK.
    return ref r1;
}

Restrizioni sull'uso delle ref readonly variabili localiRestrictions on use of ref readonly locals

Fatta eccezione per la loro readonly natura, le ref readonly variabili locali si comportano come normali ref variabili locali e sono soggette esattamente alle stesse restrizioni.Except for their readonly nature, ref readonly locals behave like ordinary ref locals and are subject to exactly same restrictions.
Ad esempio, le restrizioni relative all'acquisizione nelle chiusure, dichiarando nei async metodi o nell' safe-to-return analisi si applicano ugualmente alle ref readonly variabili locali.For example restrictions related to capturing in closures, declaring in async methods or the safe-to-return analysis equally applies to ref readonly locals.

Espressioni ternarie ref .Ternary ref expressions. (noto anche come "lvalue condizionale")(aka "Conditional LValues")

MotivazioneMotivation

L'utilizzo di e delle variabili ref ref readonly locali ha esposto la necessità di inizializzare tali variabili locali con una o un'altra variabile di destinazione in base a una condizione.Use of ref and ref readonly locals exposed a need to ref-initialize such locals with one or another target variable based on a condition.

Una soluzione alternativa tipica consiste nell'introdurre un metodo come:A typical workaround is to introduce a method like:

ref T Choice(bool condition, ref T consequence, ref T alternative)
{
    if (condition)
    {
         return ref consequence;
    }
    else
    {
         return ref alternative;
    }
}

Si noti che Choice non è una sostituzione esatta di una terna poiché tutti gli argomenti devono essere valutati nel sito di chiamata, il che ha provocato un comportamento non intuitivo e bug.Note that Choice is not an exact replacement of a ternary since all arguments must be evaluated at the call site, which was leading to unintuitive behavior and bugs.

Il codice seguente non funzionerà come previsto:The following will not work as expected:

    // will crash with NRE because 'arr[0]' will be executed unconditionally
    ref var r = ref Choice(arr != null, ref arr[0], ref otherArr[0]);

SoluzioneSolution

Consente un tipo speciale di espressione condizionale che restituisce un riferimento a uno degli argomenti LValue in base a una condizione.Allow special kind of conditional expression that evaluates to a reference to one of LValue argument based on a condition.

Uso dell' ref espressione ternaria.Using ref ternary expression.

La sintassi per la versione ref di un'espressione condizionale è <condition> ? ref <consequence> : ref <alternative>;The syntax for the ref flavor of a conditional expression is <condition> ? ref <consequence> : ref <alternative>;

Analogamente all'espressione condizionale ordinaria <consequence> o <alternative> viene valutato a seconda del risultato dell'espressione della condizione booleana.Just like with the ordinary conditional expression only <consequence> or <alternative> is evaluated depending on result of the boolean condition expression.

A differenza dell'espressione condizionale ordinaria, ref espressione condizionale:Unlike ordinary conditional expression, ref conditional expression:

  • richiede che <consequence> e <alternative> siano lvalue.requires that <consequence> and <alternative> are LValues.
  • ref l'espressione condizionale è LValue eref conditional expression itself is an LValue and
  • ref l'espressione condizionale può essere scrivibile se sia <consequence> che <alternative> sono scrivibile lvalueref conditional expression is writeable if both <consequence> and <alternative> are writeable LValues

Esempi:Examples:
ref ternaria è un LValue e, di conseguenza, può essere passato/assegnato/restituito per riferimento;ref ternary is an LValue and as such it can be passed/assigned/returned by reference;

     // pass by reference
     foo(ref (arr != null ? ref arr[0]: ref otherArr[0]));

     // return by reference
     return ref (arr != null ? ref arr[0]: ref otherArr[0]);

Essendo un LValue, può anche essere assegnato a.Being an LValue, it can also be assigned to.

     // assign to
     (arr != null ? ref arr[0]: ref otherArr[0]) = 1;

     // error. readOnlyField is readonly and thus conditional expression is readonly
     (arr != null ? ref arr[0]: ref obj.readOnlyField) = 1;

Può essere usato come ricevitore di una chiamata al metodo e ignorare la copia, se necessario.Can be used as a receiver of a method call and skip copying if necessary.

     // no copies
     (arr != null ? ref arr[0]: ref otherArr[0]).StructMethod();

     // invoked on a copy.
     // The receiver is `readonly` because readOnlyField is readonly.
     (arr != null ? ref arr[0]: ref obj.readOnlyField).StructMethod();

     // no copies. `ReadonlyStructMethod` is a method on a `readonly` struct
     // and can be invoked directly on a readonly receiver
     (arr != null ? ref arr[0]: ref obj.readOnlyField).ReadonlyStructMethod();

ref ternaria può essere usato anche in un contesto normale (non Ref).ref ternary can be used in a regular (not ref) context as well.

     // only an example
     // a regular ternary could work here just the same
     int x = (arr != null ? ref arr[0]: ref otherArr[0]);

SvantaggiDrawbacks

È possibile visualizzare due argomenti principali rispetto al supporto migliorato per i riferimenti e i riferimenti di sola lettura:I can see two major arguments against enhanced support for references and readonly references:

  1. I problemi risolti qui sono molto vecchi.The problems that are solved here are very old. Perché non è possibile risolverli rapidamente, soprattutto perché non è utile per il codice esistente?Why suddenly solve them now, especially since it would not help existing code?

Quando si trovano C# e .NET usati nei nuovi domini, alcuni problemi diventano più importanti.As we find C# and .Net used in new domains, some problems become more prominent.
Come esempi di ambienti più critici rispetto alla media dei sovraccarichi di calcolo, è possibile elencareAs examples of environments that are more critical than average about computation overheads, I can list

  • scenari di cloud/Data Center in cui il calcolo viene fatturato e la velocità di risposta è un vantaggio competitivo.cloud/datacenter scenarios where computation is billed for and responsiveness is a competitive advantage.
  • Giochi/VR/AR con requisiti di tempo reale per le latenzeGames/VR/AR with soft-realtime requirements on latencies

Questa funzionalità non sacrifica i punti di forza esistenti, ad esempio la indipendenza dai tipi, consentendo al tempo stesso di ridurre i sovraccarichi in alcuni scenari comuni.This feature does not sacrifice any of the existing strengths such as type-safety, while allowing to lower overheads in some common scenarios.

  1. È ragionevolmente possibile garantire che il chiamato venga riprodotto dalle regole quando sceglie i readonly contratti?Can we reasonably guarantee that the callee will play by the rules when it opts into readonly contracts?

Quando si usa, è presente una relazione di trust simile out .We have similar trust when using out. Un'implementazione non corretta di out può causare un comportamento non specificato, ma in realtà si verifica raramente.Incorrect implementation of out can cause unspecified behavior, but in reality it rarely happens.

Se le regole di verifica formale hanno familiarità con, è possibile ref readonly attenuare ulteriormente il problema di attendibilità.Making the formal verification rules familiar with ref readonly would further mitigate the trust issue.

AlternativiAlternatives

Il principale progetto in competizione è effettivamente "non fare nulla".The main competing design is really "do nothing".

Domande non risolteUnresolved questions

Riunioni di progettazioneDesign meetings

https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-02-22.md https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-03-01.md https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-08-28.md https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-09-25.md https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-09-27.mdhttps://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-02-22.md https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-03-01.md https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-08-28.md https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-09-25.md https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-09-27.md