Qual'è la differenza tra const e readonly in C #?


1363

Qual è la differenza tra conste readonlyin C #?

Quando useresti uno sopra l'altro?


Ho dovuto cercare diverse risposte per trovare questo link, ma è buono. L'opinione di Eric Lippert sull'immutabilità in C #
Frank Bryce il

2
@donstack, in realtà secondo il riferimento C # , Un campo di sola lettura può essere assegnato e riassegnato più volte all'interno della dichiarazione e del costruttore del campo.
Marques,

Risposte:


1289

A parte l'apparente differenza di

  • dover dichiarare il valore al momento di una definizione per un valore constVS readonlypuò essere calcolato dinamicamente ma deve essere assegnato prima che il costruttore esca .. dopo che è congelato.
  • 'const sono implicitamente static. Usi una ClassName.ConstantNamenotazione per accedervi.

C'è una sottile differenza. Considera una classe definita in AssemblyA.

public class Const_V_Readonly
{
  public const int I_CONST_VALUE = 2;
  public readonly int I_RO_VALUE;
  public Const_V_Readonly()
  {
     I_RO_VALUE = 3;
  }
}

AssemblyBfa riferimento AssemblyAe utilizza questi valori nel codice. Quando questo è compilato,

  • nel caso del constvalore, è come trovare un rimpiazzo, il valore 2 viene "inserito in" AssemblyBIL. Ciò significa che se domani aggiornerò I_CONST_VALUEa 20 in futuro. AssemblyBavrebbe ancora 2 fino a quando non lo ricompilerò .
  • nel caso del readonlyvalore, è come refa una posizione di memoria. Il valore non è inserito in AssemblyBIL. Ciò significa che se la posizione della memoria viene aggiornata, AssemblyBottiene il nuovo valore senza ricompilazione. Quindi, se I_RO_VALUEviene aggiornato a 30, devi solo creare AssemblyA. Non è necessario ricompilare tutti i client.

Quindi se sei sicuro che il valore della costante non cambierà usa a const.

public const int CM_IN_A_METER = 100;

Ma se hai una costante che può cambiare (es. Precisione scritta) .. o in caso di dubbio, usa a readonly.

public readonly float PI = 3.14;

Aggiornamento: Aku ha bisogno di farsi menzionare perché lo ha sottolineato per primo. Inoltre ho bisogno di collegare dove ho imparato questo ... Efficace C # - Bill Wagner


77
Il staticpunto sembra essere il punto più importante e utile -consts are implicitly static
LCJ

28
La parte sui valori di riferimento è la più importante. I valori costanti possono essere ottimizzati via.
Coding Barfield

22
readonlyle variabili possono essere modificate al di fuori del costruttore (riflessione). È solo il compilatore che tenta di impedirti di modificare var al di fuori del costruttore.
Bitterblue,

12
@ Le readonlyvariabili mini-me non possono essere modificate una volta terminato il costruttore, anche tramite la riflessione. Il runtime sembra non applicare questo. Il runtime capita anche di non far rispettare che non si cambia string.Emptya "Hello, world!", ma io ancora non sarebbe affermare che questo rende string.Emptymodificabili, o che il codice non deve presumere che string.Emptysarà sempre una stringa di lunghezza zero.

7
blogs.msmvps.com/jonskeet/2014/07/16/… è interessante leggere solo le spese generali di sola lettura
CAD bloke

275

C'è un gotcha con contro! Se si fa riferimento a una costante di un altro assembly, il suo valore verrà compilato direttamente nell'assembly chiamante. In questo modo quando aggiorni la costante nell'assembly di riferimento, questa non cambierà nell'assembly chiamante!


8
In caso di decompilazione (Reflector, ILSpy, ..) una costante NON È MAI MAI PIÙ referenziata da nessuno, indipendentemente dallo stesso assembly o da un altro assembly, quindi non è possibile analizzare l'utilizzo di una costante nel codice compilato.
springy76,

159

costanti

  • Le costanti sono statiche per impostazione predefinita
  • Devono avere un valore al momento della compilazione (puoi avere ad esempio 3.14 * 2, ma non puoi chiamare metodi)
  • Potrebbe essere dichiarato all'interno delle funzioni
  • Vengono copiati in ogni assembly che li utilizza (ogni assembly ottiene una copia locale dei valori)
  • Può essere utilizzato negli attributi

Campi di istanza di sola lettura

  • Deve avere impostato il valore, prima che il costruttore esca
  • Vengono valutati quando viene creata l'istanza

Campi di sola lettura statici

  • Vengono valutati quando l'esecuzione del codice raggiunge il riferimento di classe (quando viene creata una nuova istanza o viene eseguito un metodo statico)
  • Deve avere un valore valutato al termine del costruttore statico
  • Non è consigliabile mettere ThreadStaticAttribute su questi (i costruttori statici verranno eseguiti in un solo thread e imposteranno il valore per il suo thread; tutti gli altri thread avranno questo valore non inizializzato)

58

Solo per aggiungere, ReadOnly solo per i tipi di riferimento rende il riferimento in sola lettura non solo i valori. Per esempio:

public class Const_V_Readonly
{
  public const int I_CONST_VALUE = 2;
  public readonly char[] I_RO_VALUE = new Char[]{'a', 'b', 'c'};

  public UpdateReadonly()
  {
     I_RO_VALUE[0] = 'V'; //perfectly legal and will update the value
     I_RO_VALUE = new char[]{'V'}; //will cause compiler error
  }
}

Esiste un tipo di riferimento diverso da stringquello che potresti usare come costante?
springy76,

Puoi avere consttipi di riferimento diversi da string, ma la costante può avere solo il valore null.
Mike Rosoft,

40

Questo lo spiega . Riepilogo: const deve essere inizializzato al momento della dichiarazione, di sola lettura può essere inizializzato sul costruttore (e quindi avere un valore diverso a seconda del costruttore utilizzato).

EDIT: vedi il gotcha di Gishu sopra per la sottile differenza


32

const: Non può essere modificato da nessuna parte.

readonly: Questo valore può essere modificato solo nel costruttore. Non può essere modificato nelle normali funzioni.


26

C'è un piccolo gotcha con sola lettura. Un campo di sola lettura può essere impostato più volte all'interno dei costruttori. Anche se il valore è impostato in due diversi costruttori concatenati, è comunque consentito.


public class Sample {
    private readonly string ro;

    public Sample() {
        ro = "set";
    }

    public Sample(string value) : this() {
        ro = value; // this works even though it was set in the no-arg ctor
    }
}

26

Un membro costante viene definito al momento della compilazione e non può essere modificato in fase di esecuzione. Le costanti vengono dichiarate come campo, utilizzando la constparola chiave e devono essere inizializzate così come sono dichiarate.

public class MyClass
{
    public const double PI1 = 3.14159;
}

Un readonlymembro è come una costante in quanto rappresenta un valore immutabile. La differenza è che un readonlymembro può essere inizializzato in fase di esecuzione, in un costruttore, oltre a poter essere inizializzato come dichiarato.

public class MyClass1
{
     public readonly double PI2 = 3.14159;

     //or

     public readonly double PI3;

     public MyClass2()
     {
         PI3 = 3.14159;
     }
}

const

  • Non possono essere dichiarati come static(sono implicitamente statici)
  • Il valore di costante viene valutato al momento della compilazione
  • le costanti sono inizializzate solo alla dichiarazione

sola lettura

  • Possono essere a livello di istanza o statici
  • Il valore viene valutato in fase di esecuzione
  • di sola lettura può essere inizializzato in dichiarazione o tramite codice nel costruttore

6
Non possono essere statici , sono statici. Dovresti chiarire se volevi dire che non si può dichiararestatic const int i = 0;
nawfal

Puoi spiegare perché constnon è possibile effettuare dichiarazioni all'interno dei metodi?
Minh Tran,

21

Una const è una costante in fase di compilazione mentre consente in sola lettura di calcolare un valore in fase di esecuzione e impostarlo nel costruttore o nell'inizializzatore di campo. Pertanto, una "const" è sempre costante ma "readonly" è di sola lettura una volta assegnata.

Eric Lippert del team C # ha maggiori informazioni su diversi tipi di immutabilità


15

Ecco un altro link che dimostra come const non sia una versione sicura o rilevante per i tipi di riferimento.

Riepilogo :

  • Il valore della proprietà const è impostato al momento della compilazione e non può cambiare in fase di esecuzione
  • Const non può essere contrassegnato come statico: la parola chiave indica che sono statici, diversamente dai campi di sola lettura che possono.
  • Cost non può essere altro che tipi di valore (primitivi)
  • La parola chiave sola lettura contrassegna il campo come immutabile. Tuttavia, la proprietà può essere modificata all'interno del costruttore della classe
  • L'unica parola chiave di sola lettura può anche essere combinata con static per farlo agire allo stesso modo di una const (almeno in superficie). C'è una marcata differenza quando si guarda l'IL tra i due
  • i campi const sono contrassegnati come "letterali" in IL mentre readonly è "initonly"

11

Sola lettura : il valore può essere modificato tramite Ctor in fase di esecuzione. Ma non attraverso la funzione membro

Costante : per impostazione predefinita statica. Il valore non può essere modificato da nessuna parte (Ctor, Function, runtime ecc. Ovunque)


grazie per non farmi leggere 4 paragrafi solo per questi due take-away ...
Don Cheadle,


6

Credo che un constvalore sia lo stesso per tutti gli oggetti (e deve essere inizializzato con un'espressione letterale), mentre readonlypuò essere diverso per ogni istanza ...


5

Uno dei membri del team nel nostro ufficio ha fornito le seguenti indicazioni su quando usare const, static e readonly:

  • Usa const quando hai una variabile di un tipo che puoi sapere in fase di esecuzione (stringa letterale, int, double, enum, ...) che desideri che tutte le istanze o i consumatori di una classe abbiano accesso a dove il valore non dovrebbe cambiare.
  • Usa statico quando si dispone di dati a cui si desidera che tutte le istanze o i consumatori di una classe abbiano accesso a dove il valore può cambiare.
  • Utilizzare staticamente di sola lettura quando si dispone di una variabile di un tipo che non è possibile sapere in fase di runtime (oggetti) che si desidera che tutte le istanze o i consumatori di una classe abbiano accesso a dove il valore non deve cambiare.
  • Utilizzare in sola lettura quando si dispone di una variabile a livello di istanza che si saprà al momento della creazione dell'oggetto che non dovrebbe cambiare.

Un'ultima nota: un campo const è statico, ma l'inverso non è vero.


1
Penso che intendi "conversare". L'inverso sarebbe "un campo non const non statico". Che può essere vero o no. Il contrario, "un campo statico è (sempre) const" non è vero.
Michael Blackburn

5

Sono entrambi costanti, ma una const è disponibile anche al momento della compilazione. Ciò significa che un aspetto della differenza è che è possibile utilizzare variabili const come input per i costruttori di attributi, ma non solo variabili.

Esempio:

public static class Text {
  public const string ConstDescription = "This can be used.";
  public readonly static string ReadonlyDescription = "Cannot be used.";
}

public class Foo 
{
  [Description(Text.ConstDescription)]
  public int BarThatBuilds {
    { get; set; }
  }

  [Description(Text.ReadOnlyDescription)]
  public int BarThatDoesNotBuild {
    { get; set; }
  }
}

5
  • quando usare constoreadonly

    • const

      • costante di compilazione : costante assoluta , il valore è impostato durante la dichiarazione, è nel codice IL stesso
    • readonly

      • costante di runtime : può essere impostata nel costruttore / init tramite il file di configurazione App.config, ma una volta inizializzato non può essere modificato

4

Le variabili contrassegnate const sono poco più che macro #define fortemente tipizzate, al momento della compilazione i riferimenti alle variabili const vengono sostituiti con valori letterali in linea. Di conseguenza, in questo modo è possibile utilizzare solo alcuni tipi di valori di primitive incorporati. Le variabili contrassegnate in sola lettura possono essere impostate, in un costruttore, in fase di esecuzione e la loro sola lettura viene imposta anche in fase di esecuzione. Ci sono alcuni costi di prestazione minori associati a questo, ma significa che puoi usarli di sola lettura con qualsiasi tipo (anche i tipi di riferimento).

Inoltre, le variabili const sono intrinsecamente statiche, mentre le variabili di sola lettura possono essere specifiche dell'istanza se lo si desidera.


Aggiunto che i costi sono macro #define fortemente tipizzate . Altrimenti, potremmo spaventare tutte le persone in C o C ++. :-)
Jason Baker,

4

CONST

  1. la parola chiave const può essere applicata a campi o variabili locali
  2. Dobbiamo assegnare il campo const al momento della dichiarazione
  3. Nessuna memoria allocata Perché il valore const è incorporato nel codice IL stesso dopo la compilazione. È come trovare tutte le occorrenze della variabile const e sostituirla con il suo valore. Quindi il codice IL dopo la compilazione avrà valori codificati al posto delle variabili const
  4. Cost in C # sono di default statici.
  5. Il valore è costante per tutti gli oggetti
  6. Esiste un problema di controllo delle versioni della DLL - Ciò significa che ogni volta che cambiamo una variabile o proprietà const pubblica (in realtà, non dovrebbe essere modificata teoricamente), qualsiasi altra DLL o assembly che utilizza questa variabile deve essere ricostruita
  7. Solo i tipi predefiniti C # possono essere dichiarati come costanti
  8. Il campo cost non può essere passato come parametro ref o out

Sola lettura

  1. la parola chiave readonly si applica solo ai campi e non alle variabili locali
  2. Possiamo assegnare un campo di sola lettura al momento della dichiarazione o nel costruttore, non in nessun altro metodo.
  3. memoria dinamica allocata per i campi di sola lettura e possiamo ottenere il valore in fase di esecuzione.
  4. Di sola lettura appartiene all'oggetto creato in modo che sia accessibile solo tramite l'istanza della classe. Per renderlo membro della classe è necessario aggiungere una parola chiave statica prima di sola lettura.
  5. Il valore può essere diverso a seconda del costruttore utilizzato (in quanto appartiene all'oggetto della classe)
  6. Se si dichiarano tipi non primitivi (tipo di riferimento) come sola lettura il riferimento è immutabile e non l'oggetto che contiene.
  7. Poiché il valore viene ottenuto in fase di esecuzione, non vi è alcun problema di controllo delle versioni DLL con campi / proprietà di sola lettura.
  8. Possiamo passare il campo di sola lettura come parametri ref o out nel contesto del costruttore.

3

Un altro gotcha .

Dato che const funziona davvero solo con tipi di dati di base, se vuoi lavorare con una classe, potresti sentirti "costretto" a usare ReadOnly. Tuttavia, fai attenzione alla trappola! ReadOnly significa che non è possibile sostituire l'oggetto con un altro oggetto (non è possibile farlo fare riferimento a un altro oggetto). Ma qualsiasi processo che ha un riferimento all'oggetto è libero di modificare i valori all'interno dell'oggetto!

Quindi non essere confuso nel pensare che ReadOnly implica che un utente non può cambiare le cose. Non esiste una sintassi semplice in C # per impedire che un'istanza di una classe cambi i suoi valori interni (per quanto ne so).


Sì, è più un tema generale. Se hai una proprietà get only che espone un arraylist, puoi comunque modificare l'arraylist. Non è possibile impostare un diverso arraylist su quella proprietà, ma non è possibile impedire all'utente di modificare l'arraylist.
Gishu,

3

A constdeve essere hard-coded , dove come readonlypuò essere impostato nel costruttore della classe.


3

Esiste una notevole differenza tra i campi const e readonly in C # .Net

const è di default statico e deve essere inizializzato con un valore costante, che non può essere modificato in seguito. La modifica del valore non è consentita anche nei costruttori. Non può essere utilizzato con tutti i tipi di dati. Per ex DateTime. Non può essere utilizzato con il tipo di dati DateTime.

public const DateTime dt = DateTime.Today;  //throws compilation error
public const string Name = string.Empty;    //throws compilation error
public readonly string Name = string.Empty; //No error, legal

di sola lettura può essere dichiarato statico, ma non necessario. Non è necessario inizializzare al momento della dichiarazione. Il suo valore può essere assegnato o modificato tramite il costruttore. Pertanto, offre un vantaggio se utilizzato come membro della classe di istanza. Due diverse istanze possono avere un valore diverso del campo di sola lettura. Per ex -

class A
{
    public readonly int Id;

    public A(int i)
    {
        Id = i;
    }
}

Quindi il campo di sola lettura può essere inizializzato con valori specifici istantanei, come segue:

A objOne = new A(5);
A objTwo = new A(10);

Qui, l'istanza di objOne avrà il valore del campo di sola lettura come 5 e objTwo ha 10. Che non è possibile usando const.


2

Una costante verrà compilata nel consumatore come valore letterale mentre la stringa statica fungerà da riferimento al valore definito.

Come esercizio, prova a creare una libreria esterna e a consumarla in un'applicazione console, quindi modifica i valori nella libreria e ricompila (senza ricompilare il programma consumer), trascina la DLL nella directory ed esegui manualmente EXE, dovresti trovare che la stringa costante non cambia.


Dubito sinceramente che sia vero ... andrò a controllare.
ljs

questo è uno dei 50 modi specifici per migliorare il tuo C # - amazon.co.uk/Effective-Specific-Ways-Improve-Your/dp/0321245660/…
Russ Cam


@Andrew Hare - sì, ho appena controllato. Sono molto sorpreso, questo è un vero gotcha, ne sono davvero molto sorpreso, stupito che sia il caso ...!
ljs

Mi oppongo, tuttavia, all'uso del puntatore a parola qui. Non è un puntatore, è un punto di riferimento, e non v'è una differenza di C #, come si può manipolare i puntatori non gestite in modalità non sicura, quindi è importante distinguere tra i due.
ljs

2

Costante

Dobbiamo fornire il valore al campo const quando viene definito. Il compilatore salva quindi il valore della costante nei metadati dell'assembly. Ciò significa che una costante può essere definita solo per il tipo primitivo come booleano, char, byte e così via. Le costanti sono sempre considerate membri statici, non membri dell'istanza.

Sola lettura

I campi di sola lettura possono essere risolti solo in fase di esecuzione. Ciò significa che possiamo definire un valore per un valore utilizzando il costruttore per il tipo in cui viene dichiarato il campo. La verifica viene eseguita dal compilatore che i campi di sola lettura non vengono scritti da alcun metodo diverso dal costruttore.

Maggiori informazioni su entrambi spiegate qui in questo articolo


1

Principalmente; è possibile assegnare un valore a un campo statico di sola lettura a un valore non costante in fase di esecuzione, mentre a una const deve essere assegnato un valore costante.


1

Costante e di sola lettura sono simili, ma non sono esattamente gli stessi. Un campo const è una costante di compilazione, il che significa che quel valore può essere calcolato in fase di compilazione. Un campo di sola lettura consente ulteriori scenari in cui è necessario eseguire un codice durante la costruzione del tipo. Dopo la costruzione, un campo di sola lettura non può essere modificato.

Ad esempio, i membri const possono essere utilizzati per definire membri come:

struct Test
{
    public const double Pi = 3.14;
    public const int Zero = 0;
}

poiché valori come 3.14 e 0 sono costanti di tempo di compilazione. Tuttavia, considera il caso in cui definisci un tipo e desideri fornirne alcune istanze pre-fab. Ad esempio, potresti voler definire una classe Color e fornire "costanti" per colori comuni come Nero, Bianco, ecc. Non è possibile farlo con i membri const, poiché i lati di destra non sono costanti di compilazione. Si potrebbe fare questo con membri statici regolari:

public class Color
{
    public static Color Black = new Color(0, 0, 0);
    public static Color White = new Color(255, 255, 255);
    public static Color Red = new Color(255, 0, 0);
    public static Color Green = new Color(0, 255, 0);
    public static Color Blue = new Color(0, 0, 255);
    private byte red, green, blue;

    public Color(byte r, byte g, byte b) {
        red = r;
        green = g;
        blue = b;
    }
}

ma poi non c'è nulla che impedisca a un cliente di Color di confondersi con esso, magari scambiando i valori in bianco e nero. Inutile dire che ciò causerebbe costernazione per altri clienti della classe Color. La funzionalità "sola lettura" risolve questo scenario. Introducendo semplicemente la parola chiave readonly nelle dichiarazioni, preserviamo l'inizializzazione flessibile, evitando al contempo che il codice client si rovini.

public class Color
{
    public static readonly Color Black = new Color(0, 0, 0);
    public static readonly Color White = new Color(255, 255, 255);
    public static readonly Color Red = new Color(255, 0, 0);
    public static readonly Color Green = new Color(0, 255, 0);
    public static readonly Color Blue = new Color(0, 0, 255);
    private byte red, green, blue;

    public Color(byte r, byte g, byte b) {
        red = r;
        green = g;
        blue = b;
    }
}

È interessante notare che i membri const sono sempre statici, mentre un membro di sola lettura può essere statico o meno, proprio come un campo normale.

È possibile utilizzare una singola parola chiave per questi due scopi, ma ciò porta a problemi di versione o problemi di prestazioni. Supponiamo per un momento che abbiamo usato una sola parola chiave per questo (const) e uno sviluppatore ha scritto:

public class A
{
    public static const C = 0;
}

e un altro sviluppatore ha scritto codice che si basava su A:

public class B
{
    static void Main() {
        Console.WriteLine(A.C);
    }
}

Ora, il codice generato può fare affidamento sul fatto che AC è una costante di compilazione? Vale a dire, l'uso di AC può essere semplicemente sostituito dal valore 0? Se dici "sì" a questo, allora ciò significa che lo sviluppatore di A non può cambiare il modo in cui AC è inizializzato - questo lega le mani dello sviluppatore di A senza permesso. Se si dice "no" a questa domanda, si perde un'importante ottimizzazione. Forse l'autore di A è positivo che AC sarà sempre zero. L'uso di const e readonly consente allo sviluppatore di A di specificare l'intento. Ciò consente un miglior comportamento del controllo delle versioni e anche prestazioni migliori.


1

ReadOnly: il valore verrà inizializzato solo una volta dal costruttore della classe.
const: può essere inizializzato in qualsiasi funzione ma solo una volta


1

La differenza è che il valore di un campo statico di sola lettura è impostato in fase di esecuzione, quindi può avere un valore diverso per diverse esecuzioni del programma. Tuttavia, il valore di un campo const è impostato su una costante di tempo di compilazione.

Ricorda: per i tipi di riferimento, in entrambi i casi (statico e di istanza), il modificatore di sola lettura impedisce solo di assegnare un nuovo riferimento al campo. In particolare, non rende immutabile l'oggetto indicato dal riferimento.

Per i dettagli, fare riferimento alle Domande frequenti su C # su questo argomento: http://blogs.msdn.com/csharpfaq/archive/2004/12/03/274791.aspx


1

Le variabili costanti vengono dichiarate e inizializzate al momento della compilazione. Il valore non può essere modificato dopo i reparti. Le variabili di sola lettura verranno inizializzate solo dal costruttore statico della classe. Sola lettura viene utilizzata solo quando si desidera assegnare il valore in fase di esecuzione.


1

Cost : valore costante assoluto durante la durata dell'applicazione.

Di sola lettura : può essere modificato in tempo di esecuzione.


1
La tua definizione di "sola lettura" che può cambiare è errata. Immagino che per "modifica" intendevi "impostare", come "può essere impostato in fase di esecuzione".
Ahmed il

0

Una cosa da aggiungere a ciò che la gente ha detto sopra. Se si dispone di un assembly contenente un valore di sola lettura (ad es. In sola lettura MaxFooCount = 4;), è possibile modificare il valore visualizzato dagli assembly chiamanti inviando una nuova versione di tale assembly con un valore diverso (ad esempio in sola lettura MaxFooCount = 5;)

Ma con una const, verrebbe piegato nel codice del chiamante quando il chiamante veniva compilato.

Se hai raggiunto questo livello di competenza in C #, sei pronto per il libro di Bill Wagner, C # efficace: 50 modi specifici per migliorare il tuo C # che risponde in dettaglio a questa domanda (e 49 altre cose).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.