Perché String.Empty non è una costante?


189

In .Net perché String.Empty viene letto solo anziché una costante? Mi chiedo solo se qualcuno sa qual era il ragionamento alla base di quella decisione.


5
Questa domanda può risolvere questa, la breve risposta è che nessuno lo sa ...
gdoron sostiene Monica il

Sì, +1 per la risposta di Eric Lippert, grazie!
Travis,

Dato in particolare che Decimal.Zero è const (dal punto di vista dell'utente che è ...)
Hamish Grubijan,

Risposte:


149

Il motivo che static readonlyviene utilizzato invece di constè dovuto all'uso con codice non gestito, come indicato da Microsoft qui nella versione Common Source Infrastructure 2.0 di Shared Source . Il file da guardare è sscli20\clr\src\bcl\system\string.cs.

La costante vuota contiene il valore di stringa vuota. Dobbiamo chiamare il costruttore String in modo che il compilatore non lo contrassegni come letterale.

Contrassegnare questo come letterale significherebbe che non si presenta come un campo a cui possiamo accedere da nativi.

Ho trovato queste informazioni da questo utile articolo su CodeProject .


Vorrei davvero apprezzare se si può spiegare questo commento (perché Jon Skeet non poteva ...) vedi qui: stackoverflow.com/questions/8462697/...
gdoron sostiene Monica

2
@gdoron: la mia ipotesi (ed è una supposizione) è questa. Quando un valore viene definito come letterale (una costante), il suo valore viene inserito nei punti in cui viene referenziato, mentre quando non viene definito come letterale, viene referenziata l'origine del valore e il valore effettivo viene recuperato in fase di esecuzione. Ho il sospetto che quest'ultimo possa garantire che si verifichi il corretto marshalling della stringa tra nativo e .NET in fase di runtime - se fosse un valore letterale, forse il compilatore nativo dovrebbe in qualche modo estrarre il valore letterale nel suo codice nativo, che probabilmente non lo è fattibile. Questa è tutta una congettura da parte mia, però.
Jeff Yates,

7
Significa che si deve usare "", piuttosto che string.Empty per i valori dei parametri predefiniti nei metodi. Il che è leggermente fastidioso.
nicodemus13,

17
"" può sembrare un errore, mentre la stringa. Vuoto mostra intenzioni intenzionali
Christopher Stevenson,

3
@JeffYates Aggiungo che il fatto che non sia coerente è già fastidioso. La gente vedrebbe il resto del codice e si chiederebbe "perché sta usando" "qui invece di String.Empty?". Sto seriamente pensando di non usarlo String.Emptypiù solo per quel motivo.
julealgon,

24

Penso che ci sia molta confusione e cattive risposte qui.

Innanzitutto, i constcampi sono staticmembri ( non membri dell'istanza ).

Controlla la sezione 10.4 Costanti delle specifiche del linguaggio C #.

Anche se le costanti sono considerate membri statici, una dichiarazione costante non richiede né consente un modificatore statico.

Se i public constmembri sono statici, non si potrebbe considerare che una costante creerà un nuovo oggetto.

Detto questo, le seguenti righe di codice fanno esattamente la stessa cosa rispetto alla creazione di un nuovo Oggetto.

public static readonly string Empty = "";
public const string Empty = "";

Ecco una nota di Microsoft che spiega la differenza tra i 2:

La parola chiave readonly è diversa dalla parola chiave const. Un campo const può essere inizializzato solo alla dichiarazione del campo. Un campo di sola lettura può essere inizializzato nella dichiarazione o in un costruttore. Pertanto, i campi di sola lettura possono avere valori diversi a seconda del costruttore utilizzato. Inoltre, mentre un campo const è una costante di compilazione, il campo di sola lettura può essere utilizzato per le costanti di runtime, ...

Quindi trovo che l'unica risposta plausibile qui sia quella di Jeff Yates.


+1 per le parole gentili e chiarimenti riguardanti le specifiche C # su const e staticamente in sola lettura.
Jeff Yates,

17
Rileggendo questo, non sono d'accordo const stringe static readonly stringfaccio la stessa cosa. I valori costanti vengono sostituiti nel codice collegato mentre vengono referenziati i valori di sola lettura statici. Se si dispone di una constlibreria A utilizzata dalla libreria B, la libreria B sostituirà tutti i riferimenti a quella constvariabile con il suo valore letterale; se static readonlyinvece fosse quella variabile , verrebbe referenziato e il suo valore determinato in fase di esecuzione.
Jeff Yates,

3
Il punto di Jeff è importante quando si fa riferimento alle biblioteche. Se si ricompila A e lo ridistribuisce, senza ricompilare B , B utilizzerà comunque i vecchi valori.
Mark Sowul,

5
String.Empty read only instead of a constant?

Se si rende costante una stringa , il compilatore viene sostituito con la stringa effettiva ovunque la si chiami e si riempie il codice con la stessa stringa dappertutto e quando il codice viene eseguito è necessario leggere ancora e ancora quella stringa dalla memoria diversa dati.

Se lasci la tua stringa letta solo in una posizione così com'è String.Empty, il programma mantiene la stessa stringa solo in una posizione e la legge, o fai riferimento ad essa - mantenendo i dati nella memoria minima.

Inoltre, se si compila una dll usando String.Empty come const e, per qualsiasi motivo, la modifica String.Empty, la dll compilata non funzionerà più allo stesso modo, poiché costcrea il codice interno per conservare effettivamente una copia della stringa ad ogni chiamata.

Vedi questo codice per esempio:

public class OneName
{
    const string cConst = "constant string";
    static string cStatic = "static string";
    readonly string cReadOnly = "read only string";

    protected void Fun()
    {
        string cAddThemAll ;

        cAddThemAll = cConst;
        cAddThemAll = cStatic ;
        cAddThemAll = cReadOnly;    
    }
}

verrà dal compilatore come:

public class OneName
{
    // note that the const exist also here !
    private const string cConst = "constant string";
    private readonly string cReadOnly;
    private static string cStatic;

    static OneName()
    {
        cStatic = "static string";
    }

    public OneName()
    {
        this.cReadOnly = "read only string";
    }

    protected void Fun()
    {
        string cAddThemAll ;

        // look here, will replace the const string everywhere is finds it.
        cAddThemAll = "constant string";
        cAddThemAll = cStatic;
        // but the read only will only get it from "one place".
        cAddThemAll = this.cReadOnly;

    }
}

e la chiamata dell'assemblea

        cAddThemAll = cConst;
0000003e  mov         eax,dword ptr ds:[09379C0Ch] 
00000044  mov         dword ptr [ebp-44h],eax 
        cAddThemAll = cStatic ;
00000047  mov         eax,dword ptr ds:[094E8C44h] 
0000004c  mov         dword ptr [ebp-44h],eax 
        cAddThemAll = cReadOnly;
0000004f  mov         eax,dword ptr [ebp-3Ch] 
00000052  mov         eax,dword ptr [eax+0000017Ch] 
00000058  mov         dword ptr [ebp-44h],eax 

Modifica: errore di battitura corretto


Quindi, questo significa che la stringa const deve essere sempre istanziata con la classe che contiene quella const? Sembra quindi molto meglio usare la lettura statica solo allora.
il berserker il

@theberserker è meglio, ma hai tutte le opzioni da usare.
Aristos,

> allora la DLL compilata non funzionerà più allo stesso modo, perché il costo rende il codice interno per mantenere effettivamente una copia della stringa su ogni chiamata. @Aristos Non è proprio vero. Una volta compilato il codice, verrà fatto riferimento alla "copia" della stringa nel blocco TEXT dell'eseguibile e tutto il codice farà semplicemente riferimento allo stesso blocco di memoria. Ciò che hai citato nel secondo passaggio è semplicemente un passaggio intermedio.
Peter Dolkens,

@utente1533523 grazie per la nota - farò un test quando troverò del tempo per verificarlo
Aristos

Come hai ottenuto quel codice assembly? C # non viene compilato in assembly!
jv110,

0

Questa risposta esiste per scopi storici.

Originariamente:

Perché Stringè una classe e quindi non può essere una costante.

Discussione estesa:

Molte utili finestre di dialogo sono state messe a punto nel vagliare questa risposta e, anziché eliminarla, questo contenuto viene riprodotto direttamente:

In .NET, (diversamente da Java), stringa e stringa sono esattamente le stesse. E sì, puoi avere costanti letterali di stringa in .NET - DrJokepu, 3 febbraio 2009 alle 16:57

Stai dicendo che una classe non può avere costanti? - StingyJack, 3 febbraio 2009 alle 16:58

Sì, gli oggetti devono essere usati in sola lettura. Solo le strutture possono fare costanti. Penso che quando usi al stringposto del Stringcompilatore cambi la const in sola lettura per te. Tutto a che fare con la felicità dei programmatori C. - Garry Shutler, 3 febbraio 2009 alle 16:59

tvanfosson lo ha appena spiegato in modo un po 'più dettagliato. "X non può essere una costante, perché contenere Y è una classe" era un po 'troppo privo di contesto;) - Leonidas 3 febbraio 2009 alle 17:01

string.Empty è una proprietà statica che restituisce un'istanza della classe String, ovvero la stringa vuota, non la classe di stringa stessa. - Tvanfosson, 3 febbraio 2009 alle 17:01

Vuoto è un'istanza di sola lettura (non è una proprietà) della classe String. - senfo, 3 febbraio 2009 alle 17:02

Mi fa male la testa. Penso ancora di avere ragione, ma ora ne sono meno certo. Stasera sono necessarie ricerche! - Garry Shutler, 3 febbraio 2009 alle 17:07

La stringa vuota è un'istanza della classe di stringa. Vuoto è un campo statico (non una proprietà, sto corretto) sulla classe String. Fondamentalmente la differenza tra un puntatore e la cosa a cui punta. Se non fosse di sola lettura, potremmo cambiare a quale istanza si riferisce il campo vuoto. - tvanfosson, 3 febbraio 2009 alle 17:07

Garry, non devi fare nessuna ricerca. Pensaci. String è una classe. Vuoto è un'istanza di una stringa. - senfo, 3 febbraio 2009 alle 17:12

C'è qualcosa che non capisco: come mai il costruttore statico della classe String può creare un'istanza della classe String? Non è forse una specie di scenario "pollo o l'uovo"? - DrJokepu, 3 febbraio 2009 alle 17:12 5

Questa risposta sarebbe corretta per quasi tutte le altre classi tranne System.String. .NET offre molte prestazioni speciali per le stringhe e una di queste è che PUOI avere costanti di stringa, provaci. In questo caso, Jeff Yates ha la risposta corretta. - Joel Mueller, 3 febbraio 2009 alle 19:25

Come descritto nel §7.18, un'espressione costante è un'espressione che può essere completamente valutata in fase di compilazione. Poiché l'unico modo per creare un valore non nullo di un tipo di riferimento diverso da stringa è applicare il nuovo operatore e poiché il nuovo operatore non è consentito in un'espressione costante, l'unico valore possibile per le costanti dei tipi di riferimento diverso da stringa è nullo. I due precedenti commenti sono stati presi direttamente dalle specifiche del linguaggio C # e ribadiscono ciò di cui ha parlato Joel Mueller. - senfo, 4 febbraio 2009 alle 15:05 5


Per favore, vota verso il basso la risposta corretta. Se vai a Definizione, scoprirai che si trova nella classe String ed è un'istanza di String. Il fatto che sia mostrato in minuscolo è la magia del compilatore.
Garry Shutler,

Non sono stato io a sottovalutarti ma in .NET, (a differenza di Java) string e String sono esattamente le stesse. E sì, puoi avere costanti letterali di stringa in .NET
Tamas Czinege,

10
Questa risposta sarebbe corretta per quasi tutte le altre classi tranne System.String. .NET offre molte prestazioni speciali per le stringhe e una di queste è che PUOI avere costanti di stringa, provaci. In questo caso, Jeff Yates ha la risposta corretta.
Joel Mueller,

7
Ho quasi cancellato questa risposta quando ne è arrivata una molto migliore, ma vale la pena tenere la discussione in questi commenti.
Garry Shutler,

1
@Garry, sei fortunato a leggere il tuo ultimo commento, altrimenti vorrei anche votare. Una stringa ha una funzione speciale in .NET, che per quanto sia una classe ref può essere una const.
Shimmy Weitzhandler,
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.