2015-12-19 27 views
17

In C#, le stringhe sono internate. Cioè, se creo la stringa foobar e la uso una seconda volta, C# avrà solo un'istanza della stringa in memoria e sebbene avrò due riferimenti, entrambi punteranno alla stessa istanza di stringa. Questo è uno dei motivi per cui le stringhe sono e devono essere immutabili in C#.Due stringhe identiche possono essere due istanze separate in C#?

Ora, la mia domanda è, se sia possibile creare in qualche modo due stringhe identiche in modo che non vengano internate, ma che ci ritroviamo con due diverse istanze di stringa in memoria, con due indirizzi diversi, che contengono proprio stesso testo?

Se sì, come?

E, questo è qualcosa che può accadere accidentalmente, o è necessario costruire uno scenario esplicitamente per questo caso?

E, infine: Supposto che ci siano due istanze di stringa separate in memoria con lo stesso valore, sono uguali (in termini di ==)? In tal caso, come funziona ==? Prima confronta per riferimento, poi per valore o ...?

+11

"In C#, sono internati stringhe. " No non lo sono. String * costanti * sono internati. Le istanze di stringa sono internate solo se si chiama 'String.Intern'. Internare ogni stringa intermedia sarebbe molto dispendioso. –

+0

Ok, non lo sapevo. Cosa significa per due istanze di stringa che hanno lo stesso valore? Si riferiscono allo stesso "oggetto"? –

+0

@GoloRoden '==' sulle stringhe fa un confronto tra stringhe (lettera per lettera, se lo fosse) in C#. Non importa se sono internati o meno, e non importa a quale memoria si riferiscono. –

risposta

33

In C#, le stringhe sono internati.

No. In C# stringhe sono autorizzati ad essere internato. Questa è una dichiarazione molto diversa.

Cioè, se creo il foobar corda e lo uso per la seconda volta, C# avrà una sola istanza della stringa nella memoria e, anche se avrò due riferimenti, entrambi punterà allo stesso stringa di esempio

No. Anche in questo caso, in C# il runtime è permesso per decidere che uno "foobar" è lo stesso di un altro e li stagista, ma non è necessario a farlo.

Ovviamente, se si copia un riferimento, il riferimento viene copiato. Ma se si crea una seconda stringa che sembra la stessa di una stringa precedente, non è necessario che sia internata.

In pratica stringhe vengono internati quando sono letterali:

string x = "foobar"; 
string y = "foobar"; 
// x is reference equal to y 

o quando potrebbero essere calcolate identici dal compilatore:

string x = "foobar"; 
string y = "foo" + "bar"; 
// x is reference equal to y 

O quando si dice esplicitamente il runtime che vuoi internare una stringa particolare. In caso contrario, le stringhe non sono in genere internati:

string x = "foobar"; 
string y = "f" + x.Substring(1); 
// x and y are not reference equal 
+0

Inoltre, voglio menzionare che l'internamento funziona solo all'interno del confine dell'assemblaggio. Il mentore può correggermi se sbaglio. –

+1

@HamletHakobyan: buon punto. In genere i valori letterali stringa vengono internati automaticamente quando si verificano due volte nello stesso assembly, ma non necessariamente quando si verificano due valori letterali in due assembly diversi. Anche in questo caso il runtime potrebbe scegliere di farlo, ma in pratica non credo che lo faccia. –

10

Solo valori letterali stringa sono internati. L'interning run-time è costoso, quindi le stringhe create dinamicamente non sono internate (a meno che non vengano internamente esplicitate chiamando lo String.Intern).

Le seguenti stringhe di tutti sono diversi casi (è possibile controllare utilizzando object.ReferenceEquals()):

string str1 = "foo"; 
string str2 = "FOO".ToLower(); 
string str3 = new StringBuilder().Append("f").Append("oo").ToString(); 

L'operatore == è sovraccarico per string per confrontarli per valore, non con riferimento

public static bool operator == (String a, String b) 
{ 
    return String.Equals(a, b); 
} 

Quando si utilizza l'operatore ==, è necessario ricordare che gli operatori non sono polimorfici. Pertanto, se il tipo in fase di compilazione di entrambi gli operandi è string, verrà utilizzato il sovraccarico string. Se almeno uno di essi è object, il confronto di riferimento sarà effettuata

string str1 = "foo"; 
string str2 = "FOO".ToLower(); 
object str3 = str2; 
bool valueComparison = str1 == str2;  // true - the same value 
bool referenceComparison = str1 == str3; // false - different instances 
+0

'str3' non è una stringa a meno che non si aggiunga' .ToString() 'alla catena. Inoltre, potresti voler aggiungere una dimostrazione di 'Object.ReferenceEquals()' per mostrare che sono oggetti veramente diversi. –

+0

@JeroenMostert Grazie per averlo notato. –

4

Ecco un test molto semplice dimostrare che 2 stringhe equivalenti non sempre puntano allo stesso riferimento all'oggetto:

static void Main(string[] args) 
{ 
    string str1 = "foo"; 
    string str2 = "f"; 
    str2 += "oo"; 
    Console.WriteLine(str1 == str2); // prints true (value equality check) 
    Console.WriteLine(object.ReferenceEquals(str1, str2)); // prints false (reference equality check) 
} 
Problemi correlati