Cristian oggi ha parlato delle stringhe, più in particolare di come uno StringBuilder per concatenare "pezzi" di stringa offra prestazioni migliori e utilissimo spuntio, di come il tutto venga compilato.
tutto questo mi ha fatto tornare alla mente, il metodo forse meno usato della classe string, parlo di Intern ed IsInterned.
prima di vedere a cosa servono una breve premessa.
i confornti tra stringhe sono all'ordine del giorno; prendiamo ad ex:
string pippo = "ciao";
if(pippo == "ciao"){...}
confronti di questo tipo sono onerosi per il sistema, una soluzione più performante potrebbe esserre quella di controlla se i due riferimenti alle stringhe puntano allo stesso oggetto con Object:.ReferenceEquals(...), prendiamo per esempio questo codice:
string pippo = "ciao";
Console.WriteLine(Object:.ReferenceEquals("ciao",pippo));
il risultato di questo confronto è inaspettatamente true , ovvero i due riferimenti puntano allo stesso oggetto, ma perche? vediamo come vengono gestiste nel CLR le stringhe, durante l'inizzializzazione CLR crea ua tabella Hash interna in cui le chiavi sono le stringhe e i valori sono il riferimento all'oggetto nell'heap gestito, naturalmente all'inizio la tabella è vuota, alla compilazione del metodo il JIT cerca nella tabella la stringa "ciao" non trovandola crea un nuovo oggetto nell' heap gestito e aggiunge nella tabella come chiave "ciao" e come valore il riferimento, la seconda volta che il compilatore cerca "ciao" la ricerca ha esito positivo e non ci sono ulteriori operazioni.
d'urante l'esecuzione il codice richiede un riferimento alla stringa ciao, CLR lo cerca nella tabella hash lo trova e riestituisce l'eggetto creato in precedenza, il riferimento viene salvato nella variabile pippo, nella seconda riga di codice CLR ricerca nuovamente la stringa ciao la ricerca nella tabella ha naturalmente esito positivo ed il riferimento è il solito salvato in pippo.
questo per quanto le stringhe letterali incorporare nel codice, discordo diverso nel caso di stringhe costruite dinamicamente
string s1 = "ciao";
string s2 = "ci";
string s3 = s2 + "ao";
Console.WriteLine(ObjectReferenceEquals(s1,s3);
Console.WriteLine(s1.Equals(s3));
diciamolo subito, il confronfo eseguito con ObjecrefenceEquals restituisce false, mentre quello con Equals true; questo perchè la la stringa s3 non viene salvata nella tabella hash, e quindi s1 e s3 non puntano al solito oggetto, mentre effettivamente le due stringe sono uguali, naturalmente come abbiamo gia detto l'esecuzione di ObjectReferenceEquals è più performante di qualsiasi altro confronto su strighe.
ecco che entra in gioco Intern
string s1 = "ciao";
string s2 = "ci";
string s3 = s2 + "ao";
s3 = string.Intern(s3);
Console.WriteLine(ObjectReferenceEquals(s1,s3);
Console.WriteLine(s1.Equals(s3));
a questo punto ObjectReferenceEquals restituirà true, naturalmente inserire una stringa nella tabella interna ha un costo, ed abusarne può paradossalmente compromettere le prestazioni inoltre il garbage colllector non può liberale le risorse a cui fa riferimento la tabella hash interna , cosa interessante l'aggiunta di stringe interne si verifica per processo, quindi la solita stringa può essere richiamata da più AppDomain migliorando l'utilizzo della memoria.
per saperne di più consiglio la lettura del libro "Microsoft.net programmazione avanzata" di Jeffrey Richter della mondadori informatica, io lo letto più o mene già due volte.
p.s. mi sono dimenticato di parlare di IsInterned varà argomento di una prossima bloggata
Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.
- ma dove vai se il var non ..., il 19 luglio 2006 alle 14:47
- DLINQ volume due, il 15 settembre 2005 alle 15:43
- DLinq mi piace , il 15 settembre 2005 alle 10:19
- ancora stringhe, il 21 dicembre 2004 alle 15:24
- in parziale rettifica o precisazione di quanto detto(...), il 13 dicembre 2004 alle 08:00
- interfacce, implementazioni esplicite, l'1 dicembre 2004 alle 14:12