2012-02-02 16 views
16

Ci sono molte domande su questo argomento, ma nessuna (eccetto one but still a short one) ha a che fare con il seguente scenario.Statico readonly vs const - assembly diversi POV?

da C# 4 libro:

enter image description here

Marc ha anche scritto:

se si modifica il valore di un const, è necessario ricostruire tutti i clienti

Domanda:

1) Perché è così? Sono entrambi static readonly e const - static?

2) Dove i valori vengono effettivamente salvati?

3) In che modo creare un campo static readonly in realtà solve questo problema "dietro la scena"?

+2

È perché il compilatore "allinea" il valore della costante, anziché fare riferimento a una variabile proveniente da un altro assieme. – ken2k

+2

Non si sapeva mai questo comportamento delle coste tra gli assemblaggi. Buona domanda –

risposta

21

no, un const è un const, non un static - è un caso speciale, con regole diverse; è solo insieme al momento della compilazione (non runtime), ed è gestita in modo diverso

il punto cruciale qui è cosa i seguenti mezzi:

var foo = SomeType.StaticValue; 

vs

var bar = SomeType.ConstValue; 

nel primo caso, legge il valore in fase di esecuzione da SomeType, ad esempio tramite ldsfld; tuttavia, nel secondo caso, viene compilato il valore con il valore, ad es.se ConstValue sembra essere 123, poi il secondo è identica a:

var bar = 123; 

in fase di esecuzione, il fatto che proviene SomeTypenon esiste, come valore (123) è stata valutata dal compilatore e memorizzato. Quindi ha bisogno di una ricostruzione per raccogliere nuovi valori.

La modifica a static readonly significa che il "caricamento del valore da SomeType" viene mantenuto.

Così il seguente:

static int Foo() 
{ 
    return Test.Foo; 
} 
static int Bar() 
{ 
    return Test.Bar; 
} 
... 
static class Test 
{ 
    public static readonly int Foo = 123; 
    public const int Bar = 456; 
} 

compila come:

.method private hidebysig static int32 Bar() cil managed 
{ 
    .maxstack 8 
    L_0000: ldc.i4 0x1c8 
    L_0005: ret 
} 

.method private hidebysig static int32 Foo() cil managed 
{ 
    .maxstack 8 
    L_0000: ldsfld int32 ConsoleApplication2.Test::Foo 
    L_0005: ret 
} 

Si noti che nel Bar, il ldc sta caricando un valore direttamente (0x1c8 == 456), con Test completamente andato.

Per completezza, il const è realizzato con un campo statico, ma - si tratta di una letterale campo, il che significa: valutato al compilatore, non in fase di esecuzione.

.field public static literal int32 Bar = int32(0x1c8) 
.field public static initonly int32 Foo 
+0

grazie per la risposta eccellente, ma isnt const è implicitamente statico? –

+1

@Royi bene, * sì * in quanto è implementato nell'IL come un '.field ... static', e nel C# si accede come' TypeName.ConstName' - ma la cosa importante è la ** semantica **; e in termini di cosa significhi la semantica, c'è un'enorme differenza tra l'accesso a un membro statico regolare (campo/prop) e l'accesso a un membro const. –

4

Hai già risposto alla tua domanda con l'immagine a cui ti sei collegato. I campi const verranno compilati ("inline") nell'assieme, come una semplice ricerca e sostituzione. static readonly indica un campo normale che non è autorizzato a cambiare ed esiste una sola volta in memoria, ma viene comunque referenziato dalla posizione di memoria.

In .NET Framework, alle costanti non è assegnata un'area di memoria, ma i valori sono considerati invece. Pertanto, non è mai possibile assegnare una costante , ma il caricamento della costante in memoria è più efficiente perché può essere iniettato direttamente nel flusso di istruzioni. Questo elimina qualsiasi accesso alla memoria al di fuori della memoria, migliorando la località di riferimento . http://www.dotnetperls.com/optimization

6

1) const è solo risolto durante la fase di compilazione con il valore che avete fornito. Mentre static readonly è una variabile statica.

2) I valori static di solito sono memorizzati in un'area speciale nell'heap chiamato High Frequency Heap. Come ho detto in precedenza, le sostituzioni vengono sostituite al momento della compilazione.

3) rendendolo il problema static readonly risolverà il problema perché durante il runtime verrà letto un valore variabile, non un valore fornito in fase di compilazione.

24

se si modifica il valore di un const, è necessario ricostruire tutti i clienti

che non è la soluzione corretta. Se si modifica il valore di un const, non era una costante. Le costanti sono per definizione cose che non cambiano mai il loro valore. L'idea che tu voglia cambiare il valore di una costante significa che stai facendo qualcosa di logicamente impossibile, e quindi ovviamente le cose si romperanno; stai facendo qualcosa che hai detto che non avresti fatto. Se vai in giro a mentire al compilatore e fa male quando lo fai, allora smetti di mentire al compilatore.

Il prezzo dell'oro non è una costante. Il nome della tua banca non è una costante. Il numero di versione del tuo programma non è una costante. Queste cose cambiano, quindi non li rendono costanti. Le costanti sono cose come pi, o il numero di protoni in un atomo d'oro.

Le variabili sono cose che possono variare - è per questo che vengono chiamate "variabili". Le costanti sono cose che rimangono ... costanti. Se può variare, rendila una variabile. Se è costante, rendilo costante. È così semplice.

perché è quello? sia statico in lettura che const sono statici

Sicuro. Che cosa c'entra questo? "statico" in C# significa "l'elemento con nome è associato al tipo, piuttosto che con una particolare istanza del tipo". ("Statico" è quindi una scelta scadente di termini, VB lo fa meglio con "condiviso".)

Se il nome è associato al tipo o un'istanza è irrilevante alla domanda se il nome si riferisce a un costante o variabile.

dove effettivamente i valori vengono salvati in entrambi static vonon readscly?

Quando si utilizza un valore costante, il valore è "cotto in" ovunque sia utilizzata. Questo è sicuro perché non cambierà mai. Non cambierà mai perché è costante e questo è ciò che significa "costante".

Quando si utilizza una variabile, il valore della variabile viene rilevato in fase di esecuzione ogni volta. "readonly" significa semplicemente "questa variabile può essere modificata solo nel costruttore della classe o nel programma di inizializzazione del campo". È ancora una variabile. (*)

come rendere un campo statico in sola lettura - in realtà risolvere questo problema dietro la scena?

Non hai indicato quale sia il problema, quindi non so quale problema stai cercando di risolvere.


(*) i campi di sola lettura per sono considerati valori non costanti fuori il costruttore, in modo che un campo di sola lettura di tipo di valore mutabili non può essere mutato, e in modo che non si può prendere un ref a una sola lettura campo e quindi muta il riferimento.

+1

Ora capisco cosa significa questa frase !: Se menti al compilatore, otterrà la sua vendetta - Henry Spencer – kokabi

+0

La tua scrittura è molto buona. Perché non scrivere un bel libro su C#. è il mio sogno! – kokabi

+1

@ programmer1: Grazie! Ho aiutato Mark a scrivere le ultime edizioni di Essential C#, ma la maggior parte della scrittura è sua. Ho pensato di scrivere un mio libro in C#, ma è un sacco di lavoro. Inoltre, scrivo un blog sul design di C#. –

0

Suppongo che possiamo pensare a una costante come valore codificato nel nostro codice, ma con una migliore manutenzione e offerte di usabilità.