Qual è la differenza tra const
e readonly
in C #?
Quando useresti uno sopra l'altro?
Qual è la differenza tra const
e readonly
in C #?
Quando useresti uno sopra l'altro?
Risposte:
A parte l'apparente differenza di
const
VS readonly
può essere calcolato dinamicamente ma deve essere assegnato prima che il costruttore esca .. dopo che è congelato.static
. Usi una ClassName.ConstantName
notazione 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
fa riferimento AssemblyA
e utilizza questi valori nel codice. Quando questo è compilato,
const
valore, è come trovare un rimpiazzo, il valore 2 viene "inserito in" AssemblyB
IL. Ciò significa che se domani aggiornerò I_CONST_VALUE
a 20 in futuro. AssemblyB
avrebbe ancora 2 fino a quando non lo ricompilerò .readonly
valore, è come ref
a una posizione di memoria. Il valore non è inserito in AssemblyB
IL. Ciò significa che se la posizione della memoria viene aggiornata, AssemblyB
ottiene il nuovo valore senza ricompilazione. Quindi, se I_RO_VALUE
viene 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
static
punto sembra essere il punto più importante e utile -consts are implicitly static
readonly
le 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.
readonly
variabili 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.Empty
a "Hello, world!"
, ma io ancora non sarebbe affermare che questo rende string.Empty
modificabili, o che il codice non deve presumere che string.Empty
sarà sempre una stringa di lunghezza zero.
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!
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
}
}
string
quello che potresti usare come costante?
const
tipi di riferimento diversi da string, ma la costante può avere solo il valore null
.
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
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
}
}
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 const
parola chiave e devono essere inizializzate così come sono dichiarate.
public class MyClass
{
public const double PI1 = 3.14159;
}
Un readonly
membro è come una costante in quanto rappresenta un valore immutabile. La differenza è che un readonly
membro 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
static
(sono implicitamente statici)sola lettura
static const int i = 0;
const
non è possibile effettuare dichiarazioni all'interno dei metodi?
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à
Ecco un altro link che dimostra come const non sia una versione sicura o rilevante per i tipi di riferimento.
Riepilogo :
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)
Ancora un altro gotcha: i valori di sola lettura possono essere cambiati dal codice "subdolo" tramite la riflessione.
var fi = this.GetType()
.BaseType
.GetField("_someField",
BindingFlags.Instance | BindingFlags.NonPublic);
fi.SetValue(this, 1);
Posso modificare un campo privato di sola lettura in C # usando reflection?
Credo che un const
valore sia 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 usare const, static e readonly:
Un'ultima nota: un campo const è statico, ma l'inverso non è vero.
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; }
}
}
quando usare const
oreadonly
const
readonly
App.config
, ma una volta inizializzato non può essere modificatoLe 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.
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).
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.
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.
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
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.
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
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.
Cost : valore costante assoluto durante la durata dell'applicazione.
Di sola lettura : può essere modificato in tempo di esecuzione.
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).