Come altri hanno sottolineato, la mutazione degli oggetti String
è utile in alcuni rari casi. Di seguito un esempio con un utile snippet di codice.
caso d'uso/sfondo
Anche se tutti dovrebbero essere un grande fan del personaggio davvero eccellente codifica supporto che .NET ha sempre offerto, a volte potrebbe essere preferibile per ridurre il carico di, in particolare se si esegue molto roundtrapping tra caratteri (legacy) a 8 bit e stringhe gestite (ovvero in genere scenari di interoperabilità).
Come ho accennato, .NET
è particolarmente enfatico che è necessario specificare esplicitamente un testo Encoding
per qualsiasi/tutte le conversioni di dati di carattere non Unicode per/da oggetti String gestiti. Questo controllo rigoroso alla periferia è davvero encomiabile, dal momento che garantisce che una volta che hai la stringa all'interno del runtime gestito non ti devi preoccupare; tutto è solo ampio Unicode. Anche l'UTF-8 è in gran parte bandito in questo regno incontaminato.
(Per contrasto, richiamano un certo altro linguaggio di scripting popolare che notoriamente pasticciato questo settore, con conseguente alla fine in molti anni di paralleli 2.x
e 3.x
versioni, tutte a causa di grandi cambiamenti Unicode in quest'ultimo.)
Quindi, .NET
sposta tutto quel casino al limite di interoperabilità, forzando Unicode (UTF-16) una volta dentro, ma questa filosofia implica che il lavoro di codifica/decodifica fatto ("una volta per tutte") sia rigorosamente rigoroso, e per questo motivo le classi .NET Encoding/Encoder possono rappresentare un collo di bottiglia per le prestazioni. Se stai spostando molto testo da ampio (Unicode) a semplice fisso ANSI a 7 o 8 bit, ASCII, ecc. (Nota che non sto parlando di MBCS o UTF-8, dove vorresti usare gli Encoder!), il paradigma di codifica .NET potrebbe sembrare eccessivo.
Inoltre, è possibile che non si sappia o non si preoccupi di specificare Encoding
. Forse tutto quello che ti interessa è un round-trip veloce e preciso per quel low-byte di un 1623 bit. Se si look at the .NET source code, anche il System.Text.ASCIIEncoding
potrebbe essere troppo ingombrante in alcune situazioni.
Il frammento di codice ...
sottile corda: caratteri a 8-bit direttamente memorizzati in un gestito String, un 'char sottile' per carattere Unicode ampia, senza preoccuparsi Tipiche codifica/decodifica durante tutto l'intervento .
Tutti questi metodi ignorano/strisciano il byte superiore di ciascun carattere Unicode
a 16 bit, trasmettendo solo esattamente ogni byte basso esattamente così com'è. Ovviamente, il ripristino riuscito del testo Unicode dopo un round trip sarà possibile solo se quei bit superiori non sono rilevanti.
/// <summary> Convert byte array to "thin string" </summary>
public static unsafe String ToThinString(this byte[] src)
{
int c;
var ret = String.Empty;
if ((c = src.Length) > 0)
fixed (char* dst = (ret = new String('\0', c)))
do
dst[--c] = (char)src[c]; // fill new String by in-situ mutation
while (c > 0);
return ret;
}
Nella direzione appena mostrato, che è tipicamente portando dati nativi in a gestito, spesso non hanno l'array di byte gestito, quindi piuttosto che allocare una temporanea solo per lo scopo di chiamando questa funzione, è possibile elaborare i byte nativi grezzi direttamente in una stringa gestita. Come prima, questo ignora tutta la codifica dei caratteri.
I (ovvie) Campo di controlli che sarebbero necessari in questa funzione non sicuri sono eliso per chiarezza:
public static unsafe String ToThinString(byte* pSrc, int c)
{
var ret = String.Empty;
if (c > 0)
fixed (char* dst = (ret = new String('\0', c)))
do
dst[--c] = (char)pSrc[c]; // fill new String by in-situ mutation
while (c > 0);
return ret;
}
Il vantaggio di String
mutazione qui è che si evita di allocazioni temporanee scrivendo direttamente alla destinazione finale. Anche se dovessi evitare l'allocazione extra usando stackalloc
, ci sarebbe una copia non necessaria dell'intera cosa quando chiamerai il costruttore String(Char*, int, int)
: chiaramente non c'è modo di associare i dati che hai appena faticosamente preparato con un oggetto String
che non ha esisterà finché non avrai finito!
Per completezza ...
Ecco lo specchio-codice che inverte il funzionamento di tornare un array di byte (anche se questa direzione non accade per illustrare la tecnica di stringa-mutazione). Questa è la direzione che normalmente utilizzi per inviare il testo Unicode su del runtime gestito .NET
, per l'utilizzo da parte di un'app legacy.
/// <summary> Convert "thin string" to byte array </summary>
public static unsafe byte[] ToByteArr(this String src)
{
int c;
byte[] ret = null;
if ((c = src.Length) > 0)
fixed (byte* dst = (ret = new byte[c]))
do
dst[--c] = (byte)src[c];
while (c > 0);
return ret ?? new byte[0];
}
Esegui il codice e scopri tu stesso cosa succede. – Servy
Perché posso vedere solo i risultati finali e non quello che sta accadendo in memoria. – MagellanTX
Metti un breakpoint sulla riga 'cCandidateString [i] = baseString [i]' e guarda 'candidateString' cambia mentre giochi attraverso ogni iterazione. Cose divertenti! –