Membri dell'istanza di sola letturaReadonly Instance Members

Problema risolto: https://github.com/dotnet/csharplang/issues/1710Championed Issue: https://github.com/dotnet/csharplang/issues/1710

RiepilogoSummary

Consente di specificare che i singoli membri di istanza in uno struct non modificano lo stato, nello stesso modo in cui non viene specificato alcun membro dell'istanza che readonly struct modifica lo stato.Provide a way to specify individual instance members on a struct do not modify state, in the same way that readonly struct specifies no instance members modify state.

Vale la pena notare che readonly instance member != pure instance member .It is worth noting that readonly instance member != pure instance member. Un pure membro di istanza garantisce che non verrà modificato alcuno stato.A pure instance member guarantees no state will be modified. Un readonly membro di istanza garantisce solo che lo stato dell'istanza non verrà modificato.A readonly instance member only guarantees that instance state will not be modified.

Tutti i membri di istanza in un readonly struct oggetto possono essere considerati in modo implicito. readonly instance membersAll instance members on a readonly struct could be considered implicitly readonly instance members. La dichiarazione esplicita in struct non di sola readonly instance members lettura si comporterebbe nello stesso modo.Explicit readonly instance members declared on non-readonly structs would behave in the same manner. Ad esempio, creerebbe comunque copie nascoste se si chiamasse un membro di istanza (nell'istanza corrente o in un campo dell'istanza) che a sua volta non era di sola lettura.For example, they would still create hidden copies if you called an instance member (on the current instance or on a field of the instance) which was itself not-readonly.

MotivazioneMotivation

Attualmente, gli utenti hanno la possibilità di creare tipi che il compilatore impone che tutti i campi siano di sola lettura (e, per estensione, che nessun membro dell'istanza modifica readonly struct lo stato).Today, users have the ability to create readonly struct types which the compiler enforces that all fields are readonly (and by extension, that no instance members modify the state). Esistono tuttavia alcuni scenari in cui si dispone di un'API esistente che espone campi accessibili o che dispone di una combinazione di membri che modificano e non modificano.However, there are some scenarios where you have an existing API that exposes accessible fields or that has a mix of mutating and non-mutating members. In queste circostanze, non è possibile contrassegnare il tipo come readonly (si tratta di una modifica di rilievo).Under these circumstances, you cannot mark the type as readonly (it would be a breaking change).

Questo in genere non ha un impatto significativo, tranne nel caso dei in parametri.This normally doesn't have much impact, except in the case of in parameters. Con i parametri per gli struct non di sola lettura, il compilatore crea una copia del parametro per ogni chiamata al membro dell'istanza, poiché non può garantire che la chiamata non modifica lo stato in interno.With in parameters for non-readonly structs, the compiler will make a copy of the parameter for each instance member invocation, since it cannot guarantee that the invocation does not modify internal state. Questo può portare a una grande quantità di copie e a prestazioni complessive peggiori rispetto al fatto che lo struct è stato appena passato direttamente per valore.This can lead to a multitude of copies and worse overall performance than if you had just passed the struct directly by value. Per un esempio, vedere questo codice in sharplabFor an example, see this code on sharplab

Alcuni altri scenari in cui possono verificarsi copie nascoste includono static readonly fields e literals .Some other scenarios where hidden copies can occur include static readonly fields and literals. Se sono supportati in futuro, finirebbe nella stessa struttura, ovvero tutti richiedono una copia completa (alla chiamata del membro dell'istanza) se lo struct non è blittable constants contrassegnato readonly come .If they are supported in the future, blittable constants would end up in the same boat; that is they all currently necessitate a full copy (on instance member invocation) if the struct is not marked readonly.

ProgettazioneDesign

Consentire a un utente di specificare che un membro dell'istanza è, a se stesso, e non modifica lo stato dell'istanza (con tutta la verifica appropriata eseguita dal readonly compilatore, naturalmente).Allow a user to specify that an instance member is, itself, readonly and does not modify the state of the instance (with all the appropriate verification done by the compiler, of course). Ad esempio:For example:

public struct Vector2
{
    public float x;
    public float y;

    public readonly float GetLengthReadonly()
    {
        return MathF.Sqrt(LengthSquared);
    }

    public float GetLength()
    {
        return MathF.Sqrt(LengthSquared);
    }

    public readonly float GetLengthIllegal()
    {
        var tmp = MathF.Sqrt(LengthSquared);

        x = tmp;    // Compiler error, cannot write x
        y = tmp;    // Compiler error, cannot write y

        return tmp;
    }

    public readonly float LengthSquared
    {
        get
        {
            return (x * x) +
                   (y * y);
        }
    }
}

public static class MyClass
{
    public static float ExistingBehavior(in Vector2 vector)
    {
        // This code causes a hidden copy, the compiler effectively emits:
        //    var tmpVector = vector;
        //    return tmpVector.GetLength();
        //
        // This is done because the compiler doesn't know that `GetLength()`
        // won't mutate `vector`.

        return vector.GetLength();
    }

    public static float ReadonlyBehavior(in Vector2 vector)
    {
        // This code is emitted exactly as listed. There are no hidden
        // copies as the `readonly` modifier indicates that the method
        // won't mutate `vector`.

        return vector.GetLengthReadonly();
    }
}

È possibile applicare readonly alle funzioni di accesso alle proprietà per indicare che this non verranno mutate nella funzione di accesso.Readonly can be applied to property accessors to indicate that this will not be mutated in the accessor. Gli esempi seguenti hanno setter di sola lettura perché tali funzioni di accesso modificano lo stato del campo membro, ma non modificano il valore di tale campo membro.The following examples have readonly setters because those accessors modify the state of member field, but do not modify the value of that member field.

public readonly int Prop1
{
    get
    {
        return this._store["Prop1"];
    }
    set
    {
        this._store["Prop1"] = value;
    }
}

Quando readonly viene applicato alla sintassi della proprietà, significa che tutte le funzioni di accesso sono readonly .When readonly is applied to the property syntax, it means that all accessors are readonly.

public readonly int Prop2
{
    get
    {
        return this._store["Prop2"];
    }
    set
    {
        this._store["Prop2"] = value;
    }
}

Readonly può essere applicato solo alle funzioni di accesso che non modificano il tipo contenitore.Readonly can only be applied to accessors which do not mutate the containing type.

public int Prop3
{
    readonly get
    {
        return this._prop3;
    }
    set
    {
        this._prop3 = value;
    }
}

È possibile applicare readonly ad alcune proprietà implementate automaticamente, ma non avrà un effetto significativo.Readonly can be applied to some auto-implemented properties, but it won't have a meaningful effect. Il compilatore considera tutti i getter implementati automaticamente come di sola lettura indipendentemente dal fatto che la readonly parola chiave sia presente o meno.The compiler will treat all auto-implemented getters as readonly whether or not the readonly keyword is present.

// Allowed
public readonly int Prop4 { get; }
public int Prop5 { readonly get; }
public int Prop6 { readonly get; set; }

// Not allowed
public readonly int Prop7 { get; set; }
public int Prop8 { get; readonly set; }

È possibile applicare readonly agli eventi implementati manualmente, ma non a eventi simili a campi.Readonly can be applied to manually-implemented events, but not field-like events. Non è possibile applicare readonly alle singole funzioni di accesso agli eventi (add/remove).Readonly cannot be applied to individual event accessors (add/remove).

// Allowed
public readonly event Action<EventArgs> Event1
{
    add { }
    remove { }
}

// Not allowed
public readonly event Action<EventArgs> Event2;
public event Action<EventArgs> Event3
{
    readonly add { }
    readonly remove { }
}
public static readonly event Event4
{
    add { }
    remove { }
}

Altri esempi di sintassi:Some other syntax examples:

  • Membri con corpo di espressione: public readonly float ExpressionBodiedMember => (x * x) + (y * y);Expression bodied members: public readonly float ExpressionBodiedMember => (x * x) + (y * y);
  • Vincoli generici: public readonly void GenericMethod<T>(T value) where T : struct { }Generic constraints: public readonly void GenericMethod<T>(T value) where T : struct { }

Il compilatore genera il membro di istanza, come di consueto, e genera anche un attributo riconosciuto dal compilatore che indica che il membro di istanza non modifica lo stato.The compiler would emit the instance member, as usual, and would additionally emit a compiler recognized attribute indicating that the instance member does not modify state. In questo modo il parametro this nascosto diventa invece di in T ref T .This effectively causes the hidden this parameter to become in T instead of ref T.

In questo modo l'utente può chiamare in modo sicuro il metodo di istanza senza che il compilatore deve crearne una copia.This would allow the user to safely call said instance method without the compiler needing to make a copy.

Le restrizioni includono:The restrictions would include:

  • Il readonly modificatore non può essere applicato a metodi statici, costruttori o distruttori.The readonly modifier cannot be applied to static methods, constructors or destructors.
  • Il readonly modificatore non può essere applicato ai delegati.The readonly modifier cannot be applied to delegates.
  • Il readonly modificatore non può essere applicato ai membri della classe o dell'interfaccia.The readonly modifier cannot be applied to members of class or interface.

SvantaggiDrawbacks

Gli stessi svantaggi esistenti attualmente con readonly struct i metodi.Same drawbacks as exist with readonly struct methods today. Alcuni codici possono comunque causare copie nascoste.Certain code may still cause hidden copies.

NoteNotes

Può anche essere possibile usare un attributo o un'altra parola chiave.Using an attribute or another keyword may also be possible.

Questa proposta è in qualche modo correlata a (ma è più un subset di) e/o a , che hanno avuto functional purity constant expressions alcune proposte esistenti.This proposal is somewhat related to (but is more a subset of) functional purity and/or constant expressions, both of which have had some existing proposals.