Domanda

Una String è un tipo di riferimento anche se ha la maggior parte delle caratteristiche di un tipo di valore come essere immutabile e avere == sovraccaricato per confrontare il testo anziché assicurarsi che facciano riferimento allo stesso oggetto.

Perché allora la stringa non è solo un tipo di valore?

È stato utile?

Soluzione

Le stringhe non sono tipi di valore poiché possono essere enormi e devono essere archiviate nell'heap. I tipi di valore sono (ancora in tutte le implementazioni del CLR) memorizzati nello stack. Lo stack che alloca le stringhe romperebbe ogni sorta di cose: lo stack è solo 1 MB per 32 bit e 4 MB per 64 bit, dovresti mettere in scatola ogni stringa, incorrere in una penalità di copia, non puoi usare stringhe interne e usare la memoria sarebbe mongolfiera, ecc ...

(Modifica: aggiunto chiarimento sul fatto che l'archiviazione del tipo di valore sia un dettaglio di implementazione, il che porta a questa situazione in cui abbiamo un tipo con semantica di valore che non eredita da System.ValueType. Grazie Ben.)

Altri suggerimenti

Non è un tipo di valore perché le prestazioni (spazio e tempo!) sarebbero terribili se fosse un tipo di valore e il suo valore dovesse essere copiato ogni volta che veniva passato e restituito da metodi, ecc.

Ha valore semantico per mantenere sano il mondo. Riesci a immaginare quanto sarebbe difficile codificare se

string s = "hello";
string t = "hello";
bool b = (s == t);

impostare b su false? Immagina quanto sarebbe difficile codificare qualsiasi applicazione.

La distinzione tra tipi di riferimento e tipi di valore è fondamentalmente un compromesso prestazionale nella progettazione della lingua. I tipi di riferimento hanno un certo sovraccarico di costruzione, distruzione e raccolta dei rifiuti, poiché sono creati nell'heap. D'altra parte, i tipi di valore hanno un sovraccarico nelle chiamate al metodo (se la dimensione dei dati è maggiore di un puntatore), poiché l'intero oggetto viene copiato anziché solo un puntatore. Poiché le stringhe possono essere (e in genere sono) molto più grandi delle dimensioni di un puntatore, sono progettate come tipi di riferimento. Inoltre, come ha sottolineato Servy, la dimensione di un tipo di valore deve essere nota al momento della compilazione, il che non è sempre il caso delle stringhe.

La questione della mutabilità è una questione separata. Sia i tipi di riferimento che i tipi di valore possono essere mutabili o immutabili. I tipi di valore sono in genere immutabili, poiché la semantica dei tipi di valori mutabili può essere fonte di confusione.

I tipi di riferimento sono generalmente mutabili, ma possono essere progettati come immutabili se ha senso. Le stringhe sono definite immutabili perché rendono possibili alcune ottimizzazioni. Ad esempio, se la stessa stringa letterale si verifica più volte nello stesso programma (che è abbastanza comune), il compilatore può riutilizzare lo stesso oggetto.

Quindi perché " == " sovraccarico per confrontare le stringhe con il testo? Perché è la semantica più utile. Se due stringhe sono uguali per il testo, potrebbero essere o meno gli stessi riferimenti agli oggetti a causa delle ottimizzazioni. Quindi confrontare i riferimenti è abbastanza inutile, mentre confrontare i testi è quasi sempre quello che vuoi.

Parlando più in generale, Strings ha ciò che viene chiamato semantica di valore . Questo è un concetto più generale rispetto ai tipi di valore, che è un dettaglio di implementazione specifico per C #. I tipi di valore hanno una semantica di valore, ma i tipi di riferimento possono anche avere una semantica di valore. Quando un tipo ha una semantica di valore, non puoi davvero dire se l'implementazione sottostante è un tipo di riferimento o un tipo di valore, quindi puoi considerare che un dettaglio dell'implementazione.

Questa è una risposta tardiva a una vecchia domanda, ma a tutte le altre risposte manca il punto, ovvero che .NET non aveva generici fino a .NET 2.0 nel 2005.

String è un tipo di riferimento anziché un tipo di valore perché era di fondamentale importanza per Microsoft garantire che le stringhe potessero essere archiviate nel modo più efficiente in raccolte non generiche , come System.Collection.ArrayList.

La memorizzazione di un tipo di valore in una raccolta non generica richiede una conversione speciale nel tipo object che si chiama boxing. Quando CLR inscatola un tipo di valore, avvolge il valore all'interno di un System.Object e lo memorizza nell'heap gestito.

La lettura del valore dalla raccolta richiede l'operazione inversa che si chiama unboxing.

Sia il pugilato che il unboxing hanno un costo non trascurabile: il pugilato richiede un'allocazione aggiuntiva, il unboxing richiede il controllo del tipo.

Alcune risposte affermano erroneamente che string non avrebbe mai potuto essere implementato come tipo di valore poiché le sue dimensioni sono variabili. In realtà è facile implementare una stringa come una struttura di dati a lunghezza fissa usando una strategia di ottimizzazione delle stringhe di piccole dimensioni: le stringhe verrebbero archiviate direttamente in memoria come una sequenza di caratteri Unicode ad eccezione delle stringhe di grandi dimensioni che verrebbero archiviate come puntatore a un buffer esterno. Entrambe le rappresentazioni possono essere progettate per avere la stessa lunghezza fissa, ovvero la dimensione di un puntatore.

Se i generici fossero esistiti sin dal primo giorno, credo che avere una stringa come tipo di valore sarebbe probabilmente stata una soluzione migliore, con una semantica più semplice, un migliore utilizzo della memoria e una migliore localizzazione della cache. Un List<string> contenente solo piccole stringhe avrebbe potuto essere un singolo blocco contiguo di memoria.

Non solo le stringhe sono tipi di riferimento immutabili. Anche i delegati multi-cast. Ecco perché è sicuro scrivere

protected void OnMyEventHandler()
{
     delegate handler = this.MyEventHandler;
     if (null != handler)
     {
        handler(this, new EventArgs());
     }
}

Suppongo che le stringhe siano immutabili perché questo è il metodo più sicuro per lavorare con loro e allocare memoria. Perché non sono tipi di valore? Gli autori precedenti hanno ragione sulla dimensione dello stack, ecc. Aggiungerei anche che creando stringhe un tipo di riferimento consente di risparmiare sulla dimensione dell'assieme quando si utilizza la stessa stringa costante nel programma. Se si definisce

string s1 = "my string";
//some code here
string s2 = "my string";

È probabile che entrambe le istanze di " la mia stringa " la costante verrà allocata nel tuo assieme una sola volta.

Se desideri gestire le stringhe come il solito tipo di riferimento, inserisci la stringa in un nuovo StringBuilder (stringhe). Oppure usa MemoryStreams.

Se devi creare una libreria, dove ti aspetti di passare enormi stringhe nelle tue funzioni, definisci un parametro come StringBuilder o come Stream.

Inoltre, il modo in cui vengono implementate le stringhe (diverse per ogni piattaforma) e quando inizi a cucirle insieme. Come usare un StringBuilder. Alloca un buffer in cui copiare, una volta raggiunta la fine, alloca ancora più memoria, nella speranza che se si eseguono grandi prestazioni di concatenazione non saranno ostacolate.

Forse Jon Skeet può aiutarti qui?

È principalmente un problema di prestazioni.

Far sì che le stringhe si comportino come il tipo di valore LIKE aiuta a scrivere il codice, ma avere un tipo di valore sarebbe un enorme impatto sulle prestazioni.

Per uno sguardo approfondito, dai un'occhiata a un bell'articolo su stringhe nel framework .net.

Come puoi sapere string è un tipo di riferimento? Non sono sicuro che sia importante come viene implementato. Le stringhe in C # sono immutabili proprio in modo da non doverti preoccupare di questo problema.

In realtà le stringhe hanno pochissime somiglianze con i tipi di valore. Per cominciare, non tutti i tipi di valore sono immutabili, è possibile modificare il valore di un Int32 tutto ciò che si desidera e sarebbe comunque lo stesso indirizzo nello stack.

Le stringhe sono immutabili per un'ottima ragione, non hanno nulla a che fare con il fatto che sono un tipo di riferimento, ma hanno molto a che fare con la gestione della memoria. È solo più efficiente creare un nuovo oggetto quando cambia la dimensione della stringa che spostare le cose sull'heap gestito. Penso che stai mescolando tipi di valore / riferimento e concetti di oggetti immutabili.

Per quanto riguarda " == " ;: Come hai detto " == " è un sovraccarico per l'operatore, e di nuovo è stato implementato per un'ottima ragione per rendere il framework più utile quando si lavora con le stringhe.

In parole molto semplici, qualsiasi valore che abbia una dimensione definita può essere trattato come un tipo di valore.

Non è così semplice come le stringhe sono costituite da array di caratteri. Guardo le stringhe come matrici di caratteri []. Pertanto si trovano nell'heap perché la posizione della memoria di riferimento è archiviata nello stack e punta all'inizio della posizione della memoria dell'array sull'heap. La dimensione della stringa non è nota prima di essere allocata ... perfetta per l'heap.

Ecco perché una stringa è veramente immutabile perché quando la cambi anche se ha le stesse dimensioni il compilatore non lo sa e deve allocare un nuovo array e assegnare caratteri alle posizioni nell'array. Ha senso se pensi alle stringhe come a un modo in cui le lingue ti proteggono dal dover allocare memoria al volo (leggi C come la programmazione)

A rischio di ottenere un altro misterioso voto negativo... il fatto che molti menzionino lo stack e la memoria rispetto ai tipi valore e ai tipi primitivi è perché devono inserirsi in un registro nel microprocessore.Non puoi spingere o inserire qualcosa nello/dallo stack se richiede più bit di quanti ne abbia un registro... le istruzioni sono, ad esempio "pop eax" -- perché eax è largo 32 bit su un sistema a 32 bit.

I tipi primitivi a virgola mobile sono gestiti dalla FPU, che è larga 80 bit.

Tutto questo è stato deciso molto prima che esistesse un linguaggio OOP per offuscare la definizione di tipo primitivo e presumo che tipo di valore sia un termine creato appositamente per i linguaggi OOP.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top