Domanda

Qual è la differenza tra const E readonly e ne usi uno piuttosto che l'altro?

È stato utile?

Soluzione

A parte l'apparente differenza di

  • dover dichiarare il valore al momento della definizione di a const VS readonly i valori possono essere calcolati dinamicamente ma devono essere assegnati prima che il costruttore esca..dopodiché è congelato.
  • 'const sono implicitamente static.Usi a ClassName.ConstantName notazione per accedervi.

C'è una sottile differenza.Consideriamo 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 Riferimenti AssemblyA e utilizza questi valori nel codice.Quando questo sarà compilato,

  • nel caso del const value, è come una ricerca-sostituzione, il valore 2 è "integrato" nel file AssemblyBè IL.Ciò significa che se domani aggiornerò I_CONST_VALUE a 20 in futuro. AssemblyB ne avrei ancora 2 finché non lo ricompilerò.
  • nel caso del readonly valore, è come a ref in una posizione di memoria.Il valore non è integrato AssemblyBè IL.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, devi solo compilare 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 (ad es.w.r.t.precisione)..o in caso di dubbio, utilizzare a readonly.

public readonly float PI = 3.14;

Aggiornamento:Aku ha bisogno di essere menzionato perché lo ha sottolineato per primo.Inoltre devo collegare dove ho imparato questo.. Do# efficace - Bill Wagner

Altri suggerimenti

C'è un problema con le costanti!Se fai riferimento a una costante da un altro assembly, il suo valore verrà compilato direttamente nell'assembly chiamante.In questo modo quando aggiorni la costante nell'assembly di riferimento non cambierà nell'assembly chiamante!

Costanti

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

Campi dell'istanza di sola lettura

  • Deve avere un valore impostato al momento dell'uscita dal costruttore
  • Vengono valutati quando viene creata l'istanza

Campi statici di sola lettura

  • Vengono valutati quando l'esecuzione del codice raggiunge il riferimento alla 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 inserire ThreadStaticAttribute su questi (i costruttori statici verranno eseguiti in un solo thread e imposteranno il valore per il relativo thread;tutti gli altri thread avranno questo valore non inizializzato)

Giusto per aggiungere, ReadOnly per i tipi di riferimento rende solo il riferimento di sola lettura, non 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
  }
}

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

MODIFICARE:Vedi il trucco di Gishu sopra per la sottile differenza

const:Non può essere cambiato da nessuna parte.

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

C'è un piccolo problema con readonly.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
    }
}

Un membro costante viene definito in fase di compilazione e non può essere modificato in fase di esecuzione.Le costanti vengono dichiarate come campo, utilizzando il metodo const parola chiave e devono essere inizializzati così come vengono dichiarati.

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

UN readonly Il membro è come una costante in quanto rappresenta un valore immutabile.La differenza è che a readonly Il membro può essere inizializzato in fase di esecuzione, in un costruttore, oltre a poter essere inizializzato mentre viene dichiarato.

public class MyClass1
{
     public readonly double PI2 = 3.14159;

     //or

     public readonly double PI3;

     public MyClass2()
     {
         PI3 = 3.14159;
     }
}

cost

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

sola lettura

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

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

Eric Lippert del team C# dispone di ulteriori informazioni sui diversi tipi di immutabilità

Ecco un altro collegamento dimostrando come const non sia sicuro per la versione o rilevante per i tipi di riferimento.

Riepilogo:

  • Il valore della proprietà const viene impostato in fase di compilazione e non può essere modificato in fase di esecuzione
  • Const non può essere contrassegnato come statico: la parola chiave indica che sono statici, a differenza dei campi di sola lettura che possono farlo.
  • Const non può essere altro che tipi valore (primitivi).
  • La parola chiave readonly contrassegna il campo come immutabile.Tuttavia la proprietà può essere modificata all'interno del costruttore della classe
  • La parola chiave readonly only può anche essere combinata con static per farla agire allo stesso modo di 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"

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

Costante :Per impostazione predefinita statico.Il valore non può essere modificato da nessuna parte (Ctor, funzione, runtime ecc. Da nessuna parte)

Ancora un altro problema:i valori di sola lettura possono essere modificati da codice "subdolo" tramite riflessione.

var fi = this.GetType()
             .BaseType
             .GetField("_someField", 
                       BindingFlags.Instance | BindingFlags.NonPublic);
fi.SetValue(this, 1);

Posso modificare un campo ereditato di sola lettura privato in C# utilizzando la riflessione?

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

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

  • Utilizzo cost quando hai una variabile di un tipo puoi sapere in fase di esecuzione (stringa letterale, int, double, enumerazioni, ...) che desideri che tutte le istanze o i consumatori di una classe abbiano accesso a cui il valore non deve cambiare.
  • Utilizzo statico quando disponi di dati a cui desideri che tutte le istanze o i consumatori di una classe abbiano accesso a cui il valore può cambiare.
  • Utilizzo sola lettura statica quando hai una variabile di un tipo che non puoi sapere in fase di runtime (oggetti) che desideri che tutte le istanze o i consumatori di una classe abbiano accesso a cui il valore non deve cambiare.
  • Utilizzo sola lettura quando hai una variabile a livello di istanza, saprai al momento della creazione dell'oggetto che non dovrebbe cambiare.

Un'ultima nota:un campo const è statico, ma non è vero il contrario.

Sono entrambi costanti, ma è disponibile un const anche in fase di compilazione.Ciò significa che un aspetto della differenza è che è possibile utilizzare variabili const come input per i costruttori di attributi, ma non 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; }
  }
}

Le variabili contrassegnate const sono poco più che macro #define fortemente tipizzate, in fase di compilazione i riferimenti alle variabili const vengono sostituiti con valori letterali in linea.Di conseguenza solo alcuni tipi di valore primitivi incorporati possono essere utilizzati in questo modo.Le variabili contrassegnate come di sola lettura possono essere impostate, in un costruttore, in fase di esecuzione e la loro sola lettura viene applicata anche durante la fase di esecuzione.A questo è associato un piccolo costo in termini di prestazioni, ma significa che puoi utilizzare readonly 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.

Un altro capito.

Poiché const funziona davvero solo con tipi di dati di base, se vuoi lavorare con una classe, potresti sentirti "costretto" a utilizzare ReadOnly.Attenzione però alla trappola!ReadOnly significa che non puoi sostituire l'oggetto con un altro oggetto (non puoi farlo riferire a un altro oggetto).Ma qualsiasi processo che abbia un riferimento all'oggetto è libero di modificare i valori dentro l'oggetto!

Quindi non lasciarti confondere nel pensare che ReadOnly implichi che un utente non possa 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).

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

const è statico per impostazione predefinita e deve essere inizializzato con un valore costante, che non può essere modificato in seguito.Anche la modifica del valore non è consentita 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

readonly può essere dichiarato statico, ma non necessario.Non è necessario inizializzare al momento della dichiarazione.Il suo valore può essere assegnato o modificato utilizzando il costruttore.Pertanto, offre vantaggi se utilizzato come membro della classe di istanza.Due diverse istanziazioni possono avere valori diversi del campo di sola lettura.Per es-

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 objOne avrà valore del campo di sola lettura come 5 e objTwo avrà 10.Ciò non è possibile utilizzando const.

Una costante verrà 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 utilizzala in un'applicazione console, quindi modifica i valori nella libreria e ricompilala (senza ricompilare il programma consumer), rilascia la DLL nella directory ed esegui l'EXE manualmente, dovresti trovare che la stringa costante non cambia.

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 boolean, char, byte e così via.Le costanti sono sempre considerate membri statici, non membri di 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 è dichiarato il campo.La verifica viene eseguita dal compilatore che i campi di sola lettura non vengono scritti con nessun metodo diverso dal costruttore.

Maggiori informazioni su entrambi spiegato qui in questo articolo

COST

  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 sostituirle con il suo valore.Quindi il codice IL dopo la compilazione avrà valori hardcoded al posto delle variabili const
  4. Const in C# sono statici per impostazione predefinita.
  5. Il valore è costante per tutti gli oggetti
  6. Esiste un problema di versione della DLL: ciò significa che ogni volta che modifichiamo una variabile o proprietà pubblica const (in effetti, non dovrebbe essere modificata teoricamente), qualsiasi altra DLL o assembly che utilizza questa variabile deve essere ricostruito
  7. Solo i tipi incorporati C# 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 e 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. La sola lettura appartiene all'oggetto creato, quindi è possibile accedervi solo tramite l'istanza della classe.Per renderlo membro della classe dobbiamo aggiungere la parola chiave statica prima della sola lettura.
  5. Il valore può essere diverso a seconda del costruttore utilizzato (poiché appartiene all'oggetto della classe)
  6. Se dichiari un tipo non primitivo (tipo di riferimento) come di sola lettura, il riferimento è immutabile, non l'oggetto che contiene.
  7. Poiché il valore viene ottenuto in fase di esecuzione, non vi è alcun problema di versione della DLL con campi/proprietà di sola lettura.
  8. Possiamo passare il campo di sola lettura come parametri ref o out nel contesto del costruttore.

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

UN const deve essere codificato, mentre readonly può essere impostato nel costruttore della classe.

Const e readonly sono simili, ma non sono esattamente la stessa cosa.Un campo const è una costante in fase di compilazione, il che significa che quel valore può essere calcolato in fase di compilazione.Un campo di sola lettura consente scenari aggiuntivi in ​​cui parte del codice deve essere eseguito 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 desideri fornirne alcune istanze prefabbricate.Ad esempio, potresti voler definire una classe Color e fornire "costanti" per i colori comuni come Nero, Bianco, ecc.Non è possibile farlo con i membri const, poiché i lati destri non sono costanti in fase di compilazione.Si 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 cliente di Color di giocarci, magari scambiando i valori del bianco e del nero.Inutile dire che ciò causerebbe costernazione agli altri client della classe Color.La funzionalità "sola lettura" risolve questo scenario.Introducendo semplicemente la parola chiave readonly nelle dichiarazioni, preserviamo l'inizializzazione flessibile evitando al tempo stesso che il codice client si disperda.

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 di prestazioni.Supponiamo per un momento di aver utilizzato una singola parola chiave per questo (const) e che uno sviluppatore abbia 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ò basarsi sul fatto che A.C è una costante in fase di compilazione?Cioè, l'uso di A.C 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 A.C viene inizializzato: questo lega le mani dello sviluppatore di A senza permesso.Se rispondi "no" a questa domanda, perderai un'importante ottimizzazione.Forse l'autore di A è sicuro che A.C sarà sempre zero.L'uso sia di const che di readonly consente allo sviluppatore di A di specificare l'intento.Ciò consente un migliore comportamento di controllo delle versioni e anche migliori prestazioni.

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

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 diverse esecuzioni del programma.Tuttavia, il valore di un campo const è impostato su una costante di tempo di compilazione.

Ricordare:Per i tipi di riferimento, in entrambi i casi (statico e di istanza), il modificatore readonly impedisce solo di assegnare un nuovo riferimento al campo.In particolare non rende immutabile l'oggetto puntato dal riferimento.

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

Le variabili costanti vengono dichiarate e inizializzate in fase di compilazione.Il valore non può essere modificato successivamente.Le variabili di sola lettura verranno inizializzate solo dal costruttore statico della classe.La sola lettura viene utilizzata solo quando vogliamo assegnare il valore in fase di esecuzione.

Una cosa da aggiungere a quanto detto sopra.Se hai un assembly contenente un valore di sola lettura (ad es.sola lettura MaxFooCount = 4;), è possibile modificare il valore visualizzato dagli assembly chiamanti inviando una nuova versione di tale assembly con un valore diverso (ad es.sola lettura MaxFooCount = 5;)

Ma con const, verrebbe inserito 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, Effective C#:50 modi specifici per migliorare il tuo C# che risponde in dettaglio a questa domanda (e altre 49 cose).

La differenza fondamentale è che Const è l'equivalente C di #DEFINE.Il numero viene letteralmente sostituito a-la precompilatore.Readonly viene effettivamente trattato come una variabile.

Questa distinzione è particolarmente rilevante quando il progetto A dipende da una costante pubblica del progetto B.Supponiamo che il pubblico cambi costantemente.Ora la tua scelta di const/readonly avrà un impatto sul comportamento del progetto A:

Cost:il progetto A non rileva il nuovo valore (a meno che non venga ricompilato con il nuovo const, ovviamente) perché è stato compilato con le costanti sostituite.

Sola lettura:Il progetto A chiederà sempre al progetto B il suo valore variabile, quindi prenderà il nuovo valore della costante pubblica in B.

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

Spero che questo aiuti, Alan.

In parole semplici Const è il tempo di compilazione e readonly è il tempo di esecuzione.

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