Quali sono i vantaggi di contrassegnare un campo come "di sola lettura" in C #?

StackOverflow https://stackoverflow.com/questions/277010

  •  07-07-2019
  •  | 
  •  

Domanda

Quali sono i vantaggi di avere una variabile membro dichiarata come sola lettura? Sta solo proteggendo da qualcuno che cambia durante il ciclo di vita della classe o ci sono miglioramenti della velocità del compilatore grazie a questa parola chiave

È stato utile?

Soluzione

La parola chiave in sola lettura viene utilizzata per dichiarare una variabile membro una costante, ma consente di calcolare il valore in fase di esecuzione. Ciò differisce da una costante dichiarata con il modificatore const , che deve avere il valore impostato al momento della compilazione. Usando in sola lettura puoi impostare il valore del campo nella dichiarazione o nel costruttore dell'oggetto di cui fa parte il campo.

Usalo anche se non vuoi ricompilare DLL esterne che fanno riferimento alla costante (poiché viene sostituita al momento della compilazione).

Altri suggerimenti

Non credo che ci siano miglioramenti delle prestazioni usando un campo di sola lettura. È semplicemente un controllo per assicurarsi che una volta che l'oggetto è stato completamente costruito, quel campo non possa essere puntato su un nuovo valore.

Tuttavia "sola lettura" è molto diverso dagli altri tipi di semantica di sola lettura perché è applicato in fase di esecuzione dal CLR. La parola chiave readonly viene compilata fino a .initonly che è verificabile dal CLR.

Il vero vantaggio di questa parola chiave è generare strutture di dati immutabili. Le strutture di dati immutabili per definizione non possono essere modificate una volta costruite. Questo rende molto facile ragionare sul comportamento di una struttura in fase di esecuzione. Ad esempio, non vi è alcun pericolo di passare una struttura immutabile a un'altra porzione casuale di codice. Non possono mai cambiarlo, quindi puoi programmare in modo affidabile contro quella struttura.

Ecco una buona voce su uno dei vantaggi dell'immutabilità: Threading

Non ci sono evidenti vantaggi in termini di prestazioni nell'uso di in sola lettura , almeno nessuno di quelli che abbia mai visto menzionato da nessuna parte. È solo per fare esattamente come suggerisci, per impedire la modifica una volta che è stata inizializzata.

Quindi è utile in quanto ti aiuta a scrivere codice più robusto, più leggibile. Il vero vantaggio di cose come questa viene quando lavori in gruppo o per manutenzione. Dichiarare qualcosa come di sola lettura è come mettere un contratto per l'uso di quella variabile nel codice. Pensala come aggiungere documentazione allo stesso modo di altre parole chiave come internal o private , stai dicendo " questa variabile non deve essere modificata dopo l'inizializzazione " e inoltre lo stai applicando .

Quindi, se crei una classe e contrassegni alcune variabili membro di sola lettura , previeni te stesso o un altro membro del team che commette un errore in seguito quando si sta espandendo o modificando la tua classe. Secondo me, questo è un vantaggio che vale la pena avere (a scapito della complessità linguistica aggiuntiva come fa doofledorfer nei commenti).

Per dirla in termini molto pratici:

Se usi una const in dll A e dll B fa riferimento a quella const, il valore di quella const verrà compilato in dll B. Se ridistribuisci dll A con un nuovo valore per quella const, la dll B utilizzerà comunque valore originale.

Se si usa un readonly nei riferimenti dll A e dll B in sola lettura, quel readonly sarà sempre cercato in fase di esecuzione. Ciò significa che se ridistribuisci dll A con un nuovo valore per quello di sola lettura, la dll B utilizzerà quel nuovo valore.

Esiste un potenziale caso in cui il compilatore può eseguire un'ottimizzazione delle prestazioni in base alla presenza della parola chiave sola lettura.

Questo vale solo se il campo di sola lettura è anche contrassegnato come statico . In tal caso, il compilatore JIT può presumere che questo campo statico non cambierà mai. Il compilatore JIT può tenerne conto durante la compilazione dei metodi della classe.

Esempio tipico: la tua classe potrebbe avere un campo statico IsDebugLoggingEnabled che è inizializzato nel costruttore (ad es. basato su un file di configurazione). Una volta compilati i metodi effettivi JIT, il compilatore può inserire intere parti del codice quando la registrazione di debug non è abilitata.

Non ho verificato se questa ottimizzazione è effettivamente implementata nella versione corrente del compilatore JIT, quindi questa è solo una speculazione.

Tieni presente che si applica solo al valore stesso, quindi se stai utilizzando un tipo di riferimento protegge solo il riferimento dalla modifica. Lo stato dell'istanza non è protetto da sola lettura.

Non dimenticare che esiste una soluzione alternativa per ottenere i campi di sola lettura al di fuori di qualsiasi costruttore che utilizza i parametri out .

Un po 'disordinato ma:

private readonly int _someNumber;
private readonly string _someText;

public MyClass(int someNumber) : this(data, null)
{ }

public MyClass(int someNumber, string someText)
{
    Initialise(out _someNumber, someNumber, out _someText, someText);
}

private void Initialise(out int _someNumber, int someNumber, out string _someText, string someText)
{
    //some logic
}

Ulteriori discussioni qui: http: //www.adamjamesnaylor.com/2013/01/23/Setting-Readonly-Fields-From-Chained-Constructors.aspx

Se hai un valore pre-definito o pre-calcolato che deve rimanere lo stesso per tutto il programma, allora dovresti usare costante ma se hai un valore che deve essere fornito in fase di esecuzione ma una volta assegnato dovrebbe rimanere lo stesso in tutto il programma dovresti usare di sola lettura. ad esempio se devi assegnare l'ora di inizio del programma o devi memorizzare un valore fornito dall'utente all'inizializzazione dell'oggetto e devi limitarlo da ulteriori modifiche che dovresti usare di sola lettura.

Aggiunta di un aspetto di base per rispondere a questa domanda:

Le proprietà possono essere espresse in sola lettura tralasciando l'operatore set . Pertanto, nella maggior parte dei casi non sarà necessario aggiungere la parola chiave in sola lettura alle proprietà:

public int Foo { get; }  // a readonly property

Contrariamente a ciò: i campi richiedono la parola chiave di sola lettura per ottenere un effetto simile:

public readonly int Foo; // a readonly field

Quindi, uno dei vantaggi di contrassegnare un campo come di sola lettura può essere quello di raggiungere un livello di protezione dalla scrittura simile a una proprietà senza l'operatore set - senza dover cambiare il campo in una proprietà, se per qualsiasi motivo, desiderata.

Prestare attenzione con le matrici private di sola lettura. Se questi vengono esposti a un client come oggetto (potresti farlo per l'interoperabilità COM come ho fatto io), il client può manipolare i valori dell'array. Utilizzare il metodo Clone () quando si restituisce un array come oggetto.

in sola lettura può essere inizializzato al momento della dichiarazione o ottenere il suo valore solo dal costruttore. A differenza di const , deve essere inizializzato e dichiarato allo stesso tempo. in sola lettura ha tutto const ha, più l'inizializzazione del costruttore

codice https://repl.it/HvRU/1

using System;

class MainClass {
    public static void Main (string[] args) {

        Console.WriteLine(new Test().c);
        Console.WriteLine(new Test("Constructor").c);
        Console.WriteLine(new Test().ChangeC()); //Error A readonly field 
        // `MainClass.Test.c' cannot be assigned to (except in a constructor or a 
        // variable initializer)
    }


    public class Test {
        public readonly string c = "Hello World";
        public Test() {

        }

        public Test(string val) {
          c = val;
        }

        public string ChangeC() {
            c = "Method";
            return c ;
        }
    }
}

Sorprendentemente, in sola lettura può effettivamente portare a un codice più lento, come ha scoperto Jon Skeet durante il test della sua libreria Noda Time. In questo caso, un test eseguito in 20 secondi ha richiesto solo 4 secondi dopo la rimozione di sola lettura.

https: //codeblog.jonskeet.uk/2014/07/16/micro-optimization-the-surprising-inefficiency-of-readonly-fields/

Ci può essere un vantaggio in termini di prestazioni in WPF, in quanto elimina la necessità di costose DependencyProperties. Ciò può essere particolarmente utile con le raccolte

Un'altra parte interessante dell'uso della marcatura di sola lettura può essere la protezione del campo dall'inizializzazione in singleton.

ad esempio nel codice di csharpindepth :

public sealed class Singleton
{
    private static readonly Lazy<Singleton> lazy =
        new Lazy<Singleton>(() => new Singleton());

    public static Singleton Instance { get { return lazy.Value; } }

    private Singleton()
    {
    }
}

svolge solo un piccolo ruolo di protezione del campo Singleton dall'inizializzazione due volte. Un altro dettaglio è che per lo scenario menzionato non è possibile utilizzare const perché const forza la creazione durante la compilazione, ma singleton esegue la creazione in fase di esecuzione.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top