Statico di sola lettura vs const


1387

Ho letto conste static readonlycampi. Abbiamo alcune classi che contengono solo valori costanti. Utilizzato per varie cose nel nostro sistema. Quindi mi chiedo se la mia osservazione è corretta:

Questo tipo di valori costanti dovrebbe essere sempre static readonlyper tutto ciò che è pubblico? E utilizzare solo constper valori interni / protetti / privati?

Che cosa mi consiglia? Forse dovrei anche non usare i static readonlycampi, ma piuttosto usare forse le proprietà?


5
Ecco un singolo caso molto interessante che ho appena trovato a favore static readonly: prova a usare una const all'interno di una IEnumeratorche provocherebbe un irrecuperabile yield e otterrai un temuto "errore del compilatore interno" . Non ho testato il codice al di fuori di Unity3D, ma confido che si tratti di un bug mono o .NET . È comunque un problema c # .
Cregox,


8
un'altra differenza è che puoi usare una stringa const in uno switch, ma non una stringa di sola lettura statica
flagg19

7
static readonlynon può essere utilizzato switch-casenell'istruzione come casevariabile, constè necessario per questo scopo.
Mostafiz Rahman,

3
static readonlynon può essere usato anche come parametro di attributo
Dread Boy il

Risposte:


940

public static readonlyi campi sono un po 'insoliti; public staticle proprietà (con solo una get) sarebbero più comuni (forse supportate da un private static readonlycampo).

consti valori vengono masterizzati direttamente nel sito di chiamata; questo è a doppio taglio:

  • è inutile se il valore viene recuperato in fase di esecuzione, forse da config
  • se si modifica il valore di una const, è necessario ricostruire tutti i client
  • ma può essere più veloce, in quanto evita una chiamata di metodo ...
  • ... che a volte potrebbe essere stato sottolineato dalla JIT

Se il valore non cambierà mai , allora const va bene - Zeroeccetera costi ragionevoli; p Oltre a ciò, le staticproprietà sono più comuni.


13
Perché una proprietà su un campo? Se è una classe immutabile, non vedo alcuna differenza.
Michael Hedgpeth,

73
@Michael - stessi motivi di sempre; nasconde l'implementazione. Potresti scoprire (in seguito) che devi essere pigro, basato sulla configurazione, su una facciata o altro. In realtà, o spesso andrebbero bene ...
Marc Gravell

42
@CoffeeAddict per definizione, una costante non sta estraendo valori da un file di configurazione; viene masterizzato come letterale in fase di compilazione. L'unico modo in cui è possibile utilizzare una costante in fase di esecuzione è tramite la riflessione sui campi. Ogni volta che provi a usarlo, il compilatore ha già sostituito il tuo uso costante con un uso letterale ; cioè se un metodo nel tuo codice usa 6 costanti e lo controlli come IL, non ci sarà alcuna menzione di ricerche costanti; i valori letterali verranno semplicemente caricati in situ
Marc Gravell

37
@MarcGravell - ATTENZIONE: i readonlycampi non possono essere utilizzati nelle istruzioni switch / case, ma è necessario che siano const.
Luciano,

7
@didibus La modifica di un campo in una proprietà, infatti, interrompe l'API. Un campo in C # si comporta effettivamente come una variabile, mentre una proprietà in C # è un aiuto di sintassi per scrivere un metodo getter e / o un metodo setter. Questa differenza è importante quando sono coinvolti altri assiemi. Se si modifica un campo in una proprietà e gli altri assembly dipendevano da questo campo, è necessario ricompilare quegli altri assembly.
Stephen Booher,

237

Vorrei utilizzare static readonlyse il consumatore si trova in un altro assemblaggio. Avere conste il Consumatore in due assemblee diverse è un bel modo di spararti ai piedi .


5
Quindi penso che come alcuni hanno menzionato o accennato, potrebbe essere saggio usare solo const per valori che sono in realtà costanti ben note se resi pubblici, altrimenti dovrebbero essere riservati per scopi di accesso interno, protetto o privato.
jpierson,

1
@Dio Il motivo per cui esiste ancora è perché non è un problema in sé - è qualcosa di cui essere consapevoli, ma la capacità di incorporare i costi oltre i confini dell'assieme è una buona cosa per le prestazioni. È davvero solo una questione di capire davvero che "costante" significa "non cambierà mai".
Michael Stum

1
@MichaelStum Ok, non dovrei chiamarlo "un problema". Nella mia linea di lavoro, ho const e lo condivido tra assiemi ma ricompilo per ogni distribuzione o spedizione di codice. Tuttavia, questo fatto vale sicuramente la pena prenderne atto.
Dio Phung,

1
Quindi, in generale, internal consto in public static readonlybase alla visibilità desiderata.
Iiridayn,

2
@Iiridayn Sì, non è un brutto modo di vederlo. Ci sono alcuni casi limite da considerare (ad esempio, se si utilizza Reflection o se è necessario un valore su un attributo) e ci sono usi validi per public const(ad esempio, qualsiasi parte di uno standard. Ogni volta che lavoro con XML, c'è un file di spazi dei nomi con un sacco di public const string.) Ma in generale, public constdovrebbe essere usato solo dopo aver considerato correttamente le implicazioni.
Michael Stum

200

Poche cose più rilevanti da notare:

const int a

  • deve essere inizializzato.
  • l'inizializzazione deve essere in fase di compilazione .

di sola lettura int a

  • può utilizzare un valore predefinito, senza inizializzare.
  • l'inizializzazione può essere eseguita in fase di esecuzione (Modifica: solo all'interno del costruttore).

39
nel ctorsolo.
Amit Kumar Ghosh,

1
Non solo all'interno del costruttore ma anche nella dichiarazione ( docs.microsoft.com/en-us/dotnet/csharp/language-reference/… ).
deChristo,

176

Questo è solo un supplemento alle altre risposte. Non le ripeterò (ora quattro anni dopo).

Ci sono situazioni in cui a conste una non const hanno semantica diversa. Per esempio:

const int y = 42;

static void Main()
{
  short x = 42;
  Console.WriteLine(x.Equals(y));
}

stampa True, mentre:

static readonly int y = 42;

static void Main()
{
  short x = 42;
  Console.WriteLine(x.Equals(y));
}

scrive False.

Il motivo è che il metodo x.Equalsha due sovraccarichi, uno che accetta un short( System.Int16) e uno che accetta un object( System.Object). Ora la domanda è se uno o entrambi si applicano al mio yargomento.

Quando yè una costante di compilazione (letterale), il constcaso, diventa importante che esista una conversione implicita da int a short purché intsia una costante e purché il compilatore C # verifichi che il suo valore rientri nell'intervallo di un short( che 42è). Vedi Conversioni di espressioni costanti implicite nella specifica del linguaggio C #. Quindi entrambi i sovraccarichi devono essere considerati. Il sovraccarico Equals(short)è preferito (qualsiasi shortè un object, ma non tutti lo objectsono short). Quindi yviene convertito in shorte viene utilizzato quel sovraccarico. Quindi Equalsconfronta due shortdi valore identico, e questo dà true.

Quando ynon è una costante, non esiste alcuna conversione implicita da inta short. Questo perché in generale un intpotrebbe essere troppo grande per adattarsi a un short. (Esiste una conversione esplicita , ma non ho detto Equals((short)y), quindi non è rilevante.) Vediamo che si applica solo un sovraccarico, Equals(object)quello. Quindi yè inscatolato object. Quindi Equalsconfronterà a System.Int16con a System.Int32, e poiché i tipi di runtime non sono nemmeno d'accordo, ciò produrrà false.

Concludiamo che in alcuni (rari) casi, cambiare un constmembro del tipo in un static readonlycampo (o viceversa, quando ciò è possibile) può cambiare il comportamento del programma.


17
Una buona aggiunta alla risposta accettata. Vorrei aggiungere che una corretta conversione dei tipi di dati e altre linee guida simili (come provare a catturare ecc.) Dovrebbe essere un punto fermo di programmatori esperti e non essere lasciati al compilatore. Tuttavia, ho imparato qualcosa di nuovo da qui. Grazie.
Uknight,

Wow, sto programmando in C # da molto tempo e non avrei mai immaginato che una const int all'interno della gamma di un corto potesse essere implicitamente convertita in un corto. Devo dire che è piuttosto strano. Adoro C # ma queste strane incoerenze che non sembrano aggiungere molto valore ma aggiungono molto potere cerebrale necessario da considerare costantemente possono essere fastidiose, specialmente per i principianti.
Mike Marynowski,

@MikeMarynowski Abbastanza vero. Ma penso che abbiano fatto questa regola (tra le altre ragioni) per rendere short x = 42;legale la dichiarazione . Perché lì hai un int, vale a dire il letterale 42, che è implicitamente trasformato in short x. Ma poi, avrebbero potuto limitare questo solo a letterali numerici; tuttavia, hanno scelto di consentire anche cose come short x = y;dove yè definito come const int y = 42;, e poi hanno finito con questo.
Jeppe Stig Nielsen,

88

Una cosa da notare è che const è limitata ai tipi primitivi / di valore (l'eccezione è stringhe)


30
In realtà constpotrebbe essere utilizzato anche per altri tipi, tranne per il fatto che deve essere inizializzato su null, il che lo rende inutile :)
nawfal

6
eccezione come in System.Exception? :)
Memet Olsen

4
@nawfal Più precisamente, gli unici tipi di valore per i quali constpossono essere utilizzati, sono sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, bool, più eventuali enumtipi. constnon può essere utilizzato per altri tipi di valore, come DateTimeo TimeSpano BigInteger. Inoltre non può essere usato per la IntPtrstruttura (considerato da alcuni un tipo "primitivo"; il termine tipo primitivo è confuso in C #). ↵↵ constPuò essere utilizzato per tutti i tipi di riferimento . Se il tipo è string, è possibile specificare qualsiasi valore di stringa. Altrimenti, il valore deve essere null.
Jeppe Stig Nielsen

@JeppeStigNielsen - Ho recentemente avuto una discussione con SERVY su questo - ha sottolineato che si può fare qualsiasi cosa (valore e tipi di riferimento) constusando default. Per i structtipi, è un'istanza con tutti i suoi membri impostati sui valori predefiniti.
Wai Ha Lee,

28

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

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

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

Puoi dare un'occhiata al mio repository: tipi di proprietà C # .


1
Cattive notizie ... link non funzionante!
Fer R


Buoni frammenti Siam ভাই :)
Muhammad Ashikuzzaman il

25

La readonlyparola chiave è diversa dalla constparola chiave. Un constcampo può essere inizializzato solo alla dichiarazione del campo. Un readonlycampo può essere inizializzato nella dichiarazione o in un costruttore. Pertanto, i readonlycampi possono avere valori diversi a seconda del costruttore utilizzato. Inoltre, mentre un constcampo è una costante di compilazione, il readonlycampo può essere utilizzato per le costanti di runtime

Riferimento MSDN breve e chiaro qui


16

conste readonlysono simili, ma non sono esattamente gli stessi.

Un constcampo è una costante di compilazione, il che significa che quel valore può essere calcolato in fase di compilazione. Un readonlycampo abilita ulteriori scenari in cui è necessario eseguire un codice durante la costruzione del tipo. Dopo la costruzione, un readonlycampo non può essere modificato.

Ad esempio, i constmembri 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, green, blue) = (r, g, 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 readonlyparola chiave 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, green, blue) = (r, g, 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 dici "no" a questa domanda, allora manca un'ottimizzazione importante. 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.


12

La mia preferenza è quella di usare const ogni volta che posso, che come menzionato sopra è limitato alle espressioni letterali o qualcosa che non richiede valutazione.

Se mi imbatto in quella limitazione, allora ricado di sola lettura statica , con un avvertimento. Generalmente userei una proprietà statica pubblica con un getter e un campo di supporto statico privato di supporto come menziona Marc qui .


7

Cost: Cost non è altro che "costante", una variabile di cui il valore è costante ma al momento della compilazione. Ed è obbligatorio assegnargli un valore. Di default una const è statica e non possiamo cambiare il valore di una variabile const in tutto il programma.

Static ReadOnly: il valore di una variabile di tipo Statico Readonly può essere assegnato in fase di esecuzione o assegnato in fase di compilazione e modificato in fase di esecuzione. Ma il valore di questa variabile può essere modificato solo nel costruttore statico. E non può essere ulteriormente modificato. Può cambiare solo una volta in fase di esecuzione

Riferimento: c-sharpcorner


6

Un campo di sola lettura statico è vantaggioso quando si espone ad altri assiemi un valore che potrebbe cambiare in una versione successiva.

Ad esempio, supponiamo che assembly Xesponga una costante come segue:

public const decimal ProgramVersion = 2.3;

Se l'assembly fa Yriferimento Xe utilizza questa costante, il valore 2.3 verrà inserito nell'assembly Ydurante la compilazione. Ciò significa che se Xviene successivamente ricompilato con la costante impostata su 2.4, Ycontinuerà a utilizzare il vecchio valore di 2,3 finché non Yviene ricompilato. Un campo di sola lettura statico evita questo problema.

Un altro modo di vedere questo è che qualsiasi valore che potrebbe cambiare in futuro non è costante per definizione, e quindi non dovrebbe essere rappresentato come tale.


3

const:

  1. il valore deve essere indicato al momento della dichiarazione
  2. costante di tempo di compilazione

sola lettura:

  1. il valore può essere fornito al momento della dichiarazione o durante il runtime utilizzando i costruttori. Il valore può variare a seconda del costruttore utilizzato.
  2. costante di tempo di esecuzione

3

Cost : i valori delle variabili const devono essere definiti insieme alla dichiarazione e successivamente non cambierà. const è implicitamente statico, quindi senza creare un'istanza di classe possiamo accedervi. questo ha un valore al momento della compilazione

ReadOnly : valori variabili di sola lettura che possiamo definire durante la dichiarazione e l'utilizzo del costruttore in fase di esecuzione. le variabili di sola lettura non possono accedere senza istanza di classe.

Statico in sola lettura : valori variabili in sola lettura statici che possiamo definire durante la dichiarazione e solo attraverso il costruttore statico ma non con qualsiasi altro costruttore. Queste variabili sono accessibili anche senza la creazione di un'istanza di classe (come variabili statiche).

staticamente in sola lettura sarà la scelta migliore se dobbiamo consumare le variabili in diversi assiemi. Si prega di controllare i dettagli completi nel link sottostante

https://www.stum.de/2009/01/14/const-strings-a-very-convenient-way-to-shoot-yourself-in-the-foot/


Potresti dirmi perché hai votato in basso la risposta, così posso aggiornarmi così come qui.
user1756922,

Non il DV, ma può darsi che questa risposta in realtà non aggiunga nulla alle risposte già complete qui.
Marc L.

infatti, ricordiamo a Java alla fine degli anni '90 che in un progetto avevamo diverse persone che producevano diversi vasi con file di classe che interagivano (si riferivano a vicenda) e che la stringa di
costanti

2

C'è una differenza minore tra i campi const e statici di sola lettura in C # .Net

const deve essere inizializzato con valore al momento della compilazione.

const è di default statico e deve essere inizializzato con un valore costante, che non può essere modificato in seguito. 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 static 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 una volta usando il costruttore. Quindi c'è la possibilità di cambiare il valore del campo di sola lettura una volta (non importa, se è statico o meno), cosa impossibile con const.


0

Le costanti sono come suggerisce il nome, campi che non cambiano e di solito sono definiti staticamente al momento della compilazione nel codice.

Le variabili di sola lettura sono campi che possono cambiare in condizioni specifiche.

Possono essere inizializzati quando li dichiarate per la prima volta come una costante, ma di solito vengono inizializzati durante la costruzione di oggetti all'interno del costruttore.

Non possono essere modificati dopo l'inizializzazione, nelle condizioni sopra menzionate.

La sola lettura statica suona come una cattiva scelta per me poiché, se è statica e non cambia mai, quindi basta usarla const pubblica, se può cambiare allora non è una costante e quindi, a seconda delle tue esigenze, puoi usare read -solo o solo una variabile normale.

Inoltre, un'altra importante distinzione è che una costante appartiene alla classe, mentre la variabile di sola lettura appartiene all'istanza!


0

Una const (essendo determinata in fase di compilazione) può essere utilizzata nei casi in cui una lettura statica statica non può, come nelle istruzioni switch o nei costruttori di attributi. Questo perché i campi di sola lettura vengono risolti solo in fase di esecuzione e alcuni costrutti di codice richiedono l'assicurazione del tempo di compilazione. Un statico di sola lettura può essere calcolato in un costruttore, che è spesso una cosa essenziale e utile. La differenza è funzionale, come dovrebbe essere il loro uso secondo me.

In termini di allocazione della memoria, almeno con le stringhe (essendo un tipo di riferimento), non sembra esserci alcuna differenza nel fatto che entrambi sono internati e faranno riferimento a un'istanza internata.

Personalmente, il mio default è di sola lettura statico, poiché per me ha più senso semantico e logico, soprattutto perché la maggior parte dei valori non sono necessari al momento della compilazione. E, a proposito, la statica pubblica di sola lettura non è affatto insolita o insolita come afferma la risposta marcata: per esempio, System.String.Emptyè una.


0

Un'altra differenza tra dichiarare const e static in sola lettura sta nell'allocazione della memoria.

Un campo statico appartiene al tipo di un oggetto piuttosto che a un'istanza di quel tipo. Di conseguenza, una volta fatto riferimento alla classe per la prima volta, il campo statico "vivrà" nella memoria per il resto del tempo e la stessa istanza del campo statico verrebbe referenziata da tutte le istanze del tipo.

D'altra parte, un campo const "appartiene a un'istanza del tipo.

Se la memoria della deallocazione è più importante per te, preferisci usare const . Se la velocità, quindi utilizzare staticamente in sola lettura .

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.