c# - Qual è la differenza tra const e readonly?




15 Answers

A parte l'apparente differenza di

  • dovendo dichiarare il valore al momento di una definizione per un valore const VS readonly può essere calcolato dinamicamente, ma deve essere assegnato prima che il costruttore esca .. dopo che è stato congelato.
  • 'const sono implicitamente static . Si utilizza una notazione ClassName.ConstantName 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;
  }
}

AssemblyB riferimento a AssemblyA e utilizza questi valori nel codice. Quando questo è compilato,

  • nel caso del valore const , è come un find-replace, il valore 2 è "inserito" AssemblyB di AssemblyB . Ciò significa che se domani aggiornerò I_CONST_VALUE a 20 in futuro. AssemblyB avrebbe ancora 2 fino a quando lo ricompilerò .
  • nel caso del valore readonly , è come un riferimento a una posizione di memoria. Il valore non è cotto nell'IL di AssemblyB . Ciò significa che se la posizione di memoria viene aggiornata, AssemblyB ottiene il nuovo valore senza ricompilazione. Quindi, se I_RO_VALUE viene aggiornato a 30, è sufficiente creare AssemblyA . Non è necessario ricompilare tutti i client.

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

public const int CM_IN_A_METER = 100;

Ma se hai una costante che può cambiare (egwrt precision) .. o in caso di dubbio, usa un readonly .

public readonly float PI = 3.14;

Aggiornamento: Aku ha bisogno di un cenno coz che ha sottolineato prima questo. Inoltre ho bisogno di collegare dove ho imparato questo .. Efficace C # - Bill Wagner

Qual è la differenza tra const e readonly e usi l'una rispetto all'altra?




costanti

  • Le costanti sono statiche per impostazione predefinita
  • Devono avere un valore in fase di compilazione (si può avere ad es. 3,14 * 2, ma non è possibile chiamare metodi)
  • Potrebbe essere dichiarato all'interno delle funzioni
  • Vengono copiati in ogni assembly che li utilizza (ogni assembly riceve una copia locale dei valori)
  • Può essere utilizzato negli attributi

Campi di istanza di sola lettura

  • Deve avere un valore impostato, al momento della chiusura del costruttore
  • Vengono valutati quando viene creata l'istanza

Campi statici di sola lettura

  • 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 quando viene eseguito il costruttore statico
  • Non è consigliabile inserire ThreadStaticAttribute su questi (i costruttori statici saranno eseguiti in un solo thread e imposteranno il valore per il suo thread, tutti gli altri thread avranno questo valore non inizializzato)



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

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




C'è un piccolo trucco con readonly. Un campo di sola lettura può essere impostato più volte all'interno del / i costruttore / i. Anche se il valore è impostato su due diversi costruttori concatenati, è ancora 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
    }
}



Un const è una costante in fase di compilazione mentre readonly consente di calcolare un valore in fase di esecuzione e impostato nel programma di inizializzazione costruttore o campo. Quindi, un 'const' è sempre costante ma 'readonly' è di sola lettura una volta assegnato.

Eric Lippert del team C # ha più informazioni sui diversi tipi di immutabilità







Credo che un valore const sia lo stesso per tutti gli oggetti (e debba essere inizializzato con un'espressione letterale), mentre readonly può essere diverso per ogni istanza ...




Sono entrambi costanti, ma un const è disponibile anche in fase di compilazione. Ciò significa che un aspetto della differenza è che è possibile utilizzare le variabili const come input per attribuire i costruttori, ma non per le variabili di sola lettura.

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; }
  }
}



Un altro pasticcio .

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

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




Una costante sarà compilata nel consumatore come valore letterale mentre la stringa statica servirà come riferimento al valore definito.

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




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




Const e readonly sono simili, ma non sono esattamente gli stessi. Un campo const è una costante in fase di compilazione, il che significa che quel valore può essere calcolato in fase di compilazione. Un campo readonly abilita scenari aggiuntivi in ​​cui alcuni codici devono essere eseguiti 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 in fase di compilazione. Tuttavia, considera il caso in cui definisci un tipo e vuoi fornire alcune istanze prefabbricate. Ad esempio, potresti voler definire una classe di colori e fornire "costanti" per i colori comuni come nero, bianco, ecc. Non è possibile farlo con i membri const, poiché i lati a destra non sono costanti in fase di compilazione. Uno potrebbe farlo 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 client di Color di utilizzarlo, magari scambiando i valori in bianco e nero. Inutile dire che ciò causerebbe costernazione per altri clienti della classe Color. La funzione "readonly" affronta questo scenario. Semplicemente introducendo la parola chiave readonly nelle dichiarazioni, preserviamo l'inizializzazione flessibile evitando al contempo il codice del client.

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 readonly può essere statico o meno, proprio come un campo normale.

È possibile utilizzare una singola parola chiave per questi due scopi, ma ciò comporta problemi di versioni 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 uno sviluppatore diverso ha scritto un codice basato su A:

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

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




La differenza è che il valore di un campo statico di sola lettura viene impostato in fase di esecuzione, quindi può avere un valore diverso per le 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 istanza), il modificatore di sola lettura ti impedisce solo di assegnare un nuovo riferimento al campo. In particolare, non rende immutabile l'oggetto indicato dal riferimento.

Per i dettagli, consultare le domande frequenti su C # su questo argomento: http://blogs.msdn.com/csharpfaq/archive/2004/12/03/274791.aspx




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 Poiché 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 hardcoded al posto delle variabili const
  4. Costante in C # sono di default statici.
  5. Il valore è costante per tutti gli oggetti
  6. C'è un problema di versioning di dll - Questo significa che ogni volta che cambiamo una variabile const o una proprietà pubblica, (infatti, non dovrebbe essere modificato teoricamente), qualsiasi altra dll o assembly che usa questa variabile deve essere ricostruita
  7. Solo i tipi di C # built-in possono essere dichiarati come costanti
  8. Il campo Const non può essere passato come parametro ref o out

Sola lettura

  1. la parola chiave readonly si applica solo ai campi non alle variabili locali
  2. Possiamo assegnare un campo di sola lettura al momento della dichiarazione o nel costruttore, non in altri metodi.
  3. memoria dinamica allocata per campi di sola lettura e possiamo ottenere il valore in fase di esecuzione.
  4. L'elemento Readonly appartiene all'oggetto creato in modo tale da essere accessibile tramite l'istanza di classe. Per renderlo membro della classe dobbiamo aggiungere la parola chiave static prima di readonly.
  5. Il valore può essere diverso a seconda del costruttore utilizzato (in quanto appartiene all'oggetto della classe)
  6. Se dichiari un tipo non primitivo (tipo di riferimento) come solo readonly, il riferimento è immutabile e non l'oggetto che contiene.
  7. Poiché il valore viene ottenuto in fase di esecuzione, non vi è alcun problema di versionamento di DLL con campi / proprietà readonly.
  8. Possiamo passare il campo di sola lettura come parametri di ref o out nel contesto del costruttore.



La differenza principale è che Const è l'equivalente in C di #DEFINE. Il numero viene letteralmente sostituito con un pre-compilatore. Readonly è in realtà trattato come una variabile.

Questa distinzione è particolarmente rilevante quando si dispone del Progetto A in base a una costante pubblica del Progetto B. Supponiamo che le modifiche alla costante pubblica. Ora la tua scelta di const / readonly avrà un impatto sul comportamento del progetto A:

Const: il progetto A non acquisisce il nuovo valore (a meno che non venga ricompilato con il nuovo const, ovviamente) perché è stato compilato con le costanti sottotitolate in.

ReadOnly: il progetto A richiederà sempre il progetto B per il suo valore variabile, quindi raccoglierà il nuovo valore della costante pubblica in B.

Onestamente, ti consiglierei di usare readonly per quasi tutto tranne le costanti veramente universali (es. Pi, Inches_To_Centimeters). Per tutto ciò che potrebbe cambiare, dico usare readonly.

Spero che questo aiuti, Alan.




Related