[c#] Statico readonly vs const


Answers

static readonly se il consumatore è in un assembly diverso. Avere il const e il Consumer in due gruppi diversi è un buon modo per sparare ai piedi .

Question

Ho letto in giro sui campi const e static readonly . Abbiamo alcune classi che contengono solo valori costanti. Utilizzato per varie cose nel nostro sistema. Quindi mi chiedo se la mia osservazione sia corretta:

Questo tipo di valori costanti dovrebbe sempre essere static readonly per tutto ciò che è pubblico? E usi solo const per valori interni / protetti / privati?

Che cosa mi consiglia? Dovrei forse anche non usare static readonly campi static readonly , ma piuttosto usare le proprietà forse?




Le costanti sono come suggerisce il nome, i campi che non cambiano e di solito sono definiti staticamente in fase di compilazione nel codice.

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

Possono essere inizializzati quando li si dichiara 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.

Static read-only suona come una scelta sbagliata per me, se è statico e non cambia mai, quindi basta usarlo public const, se può cambiare quindi non è una costante e quindi, a seconda delle esigenze, puoi usare read -solo o solo una variabile regolare.

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




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

Ad esempio, supponiamo che l'assemblaggio X esponga una costante come segue:

public const decimal ProgramVersion = 2.3;

Se l'assemblaggio Y riferimento a X e usa questa costante, il valore 2.3 sarà cotto nell'assemblaggio Y momento della compilazione. Ciò significa che se X viene successivamente ricompilato con la costante impostata su 2.4, Y utilizzerà comunque il vecchio valore di 2.3 finché non viene ricompilato Y Un campo statico di sola lettura evita questo problema.

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




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

Ci sono situazioni in cui un const e un non-const hanno una 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.Equals ha due overload, uno che richiede un short ( System.Int16 ) e uno che accetta un object ( System.Object ). Ora la domanda è se uno o entrambi si applicano al mio argomento y .

Quando y è una costante in fase di compilazione (letterale), il caso const , diventa importante che esista una conversione implicita da int a short condizione che l' int sia una costante e che il compilatore C # verifichi che il suo valore sia all'interno il raggio di un short (che è 42 ). Vedi Conversazioni con 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 gli object sono short ). Quindi y viene convertito in short e viene usato quel overload. Quindi Equals confronta due short di valore identico, e ciò dà true .

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

Concludiamo che in alcuni (rari) casi, la modifica di un membro di tipo const in un campo static readonly (o l'altro modo, quando è possibile) può modificare il comportamento del programma.




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 parola chiave readonly è diversa dalla parola chiave const . Un campo const può essere inizializzato solo alla dichiarazione del campo. Un campo di readonly può essere inizializzato o alla dichiarazione o in un costruttore. Pertanto, i campi di readonly possono avere valori diversi a seconda del costruttore utilizzato. Inoltre, mentre un campo const è una costante in fase di compilazione, il campo readonly può essere utilizzato per le costanti di runtime

Riferimento MSDN breve e chiaro qui




const:

  1. il valore dovrebbe essere dato al momento della dichiarazione
  2. compilare costante di tempo

sola lettura:

  1. il valore può essere fornito in base alla dichiarazione o durante il runtime utilizzando i costruttori. Il valore può variare in base al costruttore utilizzato.
  2. tempo costante di esecuzione



Links



Tags

c# c#   constants