Domanda

Qualcuno può fornire un esempio di un buon momento per utilizzare effettivamente "unsafe" e "fixed" nel codice C#?Ci ho già giocato, ma non ne ho mai trovato un buon utilizzo.

Considera questo codice...

fixed (byte* pSrc = src, pDst = dst) {
    //Code that copies the bytes in a loop
}

rispetto al semplice utilizzo...

Array.Copy(source, target, source.Length);

Il secondo è il codice trovato nel .NET Framework, il primo una parte di codice copiato dal sito Microsoft, http://msdn.microsoft.com/en-us/library/28k1s2k6(VS.80).aspx.

Array.Copy() integrato è notevolmente più veloce rispetto all'utilizzo del codice Unsafe.Ciò potrebbe essere dovuto solo al fatto che il secondo è scritto meglio e il primo è solo un esempio, ma di quali tipi di situazioni avresti davvero bisogno per utilizzare il codice Unsafe/Fixed per qualsiasi cosa?Oppure questo povero sviluppatore web sta scherzando con qualcosa sopra la sua testa?

È stato utile?

Soluzione

È utile per l'interoperabilità con codice non gestito.Tutti i puntatori passati a funzioni non gestite devono essere corretti (aka.bloccato) per impedire al Garbage Collector di riposizionare la memoria sottostante.

Se stai utilizzando P/Invoke, il marshaller predefinito aggiungerà gli oggetti per te.A volte è necessario eseguire il marshalling personalizzato e talvolta è necessario bloccare un oggetto per un periodo superiore alla durata di una singola chiamata P/Invoke.

Altri suggerimenti

Ho utilizzato blocchi non sicuri per manipolare i dati bitmap.L'accesso al puntatore non elaborato è significativamente più veloce di SetPixel/GetPixel.

unsafe
{
    BitmapData bmData = bm.LockBits(...)
    byte *bits = (byte*)pixels.ToPointer();
    // Do stuff with bits
}

I termini "risolto" e "non sicuro" vengono in genere utilizzati durante l'interoperabilità o quando sono necessarie prestazioni aggiuntive.Cioè.String.CopyTo() utilizza unsafe e Fixed nella sua implementazione.

comportamento in stile reinterpret_cast

Se stai manipolando un po', questo può essere incredibilmente utile

molte implementazioni di hashcode ad alte prestazioni utilizzano UInt32 per il valore hash (questo rende gli spostamenti più semplici).Poiché .Net richiede Int32 per il metodo, desideri convertire rapidamente uint in int.Poiché non è importante quale sia il valore effettivo, si desidera solo che tutti i bit nel valore siano preservati e si desidera eseguire un cast di reinterpretazione.

public static unsafe int UInt32ToInt32Bits(uint x)
{
    return *((int*)(void*)&x);
}

notare che la denominazione è modellata su BitConverter.DoubleToInt64Bits

Continuando nel filone dell'hashing, la conversione di una struttura basata su stack in un byte* consente un facile utilizzo delle funzioni di hashing per byte:

// from the Jenkins one at a time hash function
private static unsafe void Hash(byte* data, int len, ref uint hash)
{
    for (int i = 0; i < len; i++)
    {
        hash += data[i];
        hash += (hash << 10);
        hash ^= (hash >> 6);
    }
}

public unsafe static void HashCombine(ref uint sofar, long data)
{
    byte* dataBytes = (byte*)(void*)&data;
    AddToHash(dataBytes, sizeof(long), ref sofar);
}

unsafe inoltre (dalla versione 2.0 in poi) consente di utilizzare stackalloc.Ciò può essere molto utile in situazioni ad alte prestazioni in cui è necessario un piccolo array di lunghezza variabile come spazio temporaneo.

Tutti questi usi sarebbero fermamente nel "solo se la tua applicazione ha davvero bisogno di prestazioni" e quindi sono inappropriati nell'uso generale, ma a volte ne hai davvero bisogno.

fix è necessario quando si desidera interoperare con qualche utile funzione non gestita (ce ne sono molte) che accetta array o stringhe in stile c.In quanto tale, non è solo per ragioni di prestazioni ma anche per ragioni di correttezza in scenari di interoperabilità.

Unsafe è utile (ad esempio) per estrarre rapidamente i dati dei pixel da un'immagine utilizzando LockBits.Il miglioramento delle prestazioni rispetto a questa operazione utilizzando l'API gestita è di diversi ordini di grandezza.

Abbiamo dovuto utilizzare una correzione quando un indirizzo viene passato a una DLL C legacy.Poiché la DLL manteneva un puntatore interno tra le chiamate di funzione, si scatenerebbe l'inferno se il GC compattasse l'heap e spostasse le cose.

Credo che venga utilizzato codice non sicuro se si desidera accedere a qualcosa al di fuori del runtime .NET, ad es.non è codice gestito (nessuna garbage collection e così via).Ciò include chiamate grezze all'API di Windows e tutto quel jazz.

Questo mi dice che i progettisti del framework .NET hanno fatto un buon lavoro nel coprire lo spazio problematico, assicurandosi che l'ambiente del "codice gestito" possa fare tutto ciò che è tradizionale (ad es.C++) può fare con il suo codice/puntatori non sicuri.Nel caso in cui ciò non sia possibile, le funzionalità non sicure/corrette sono disponibili se ne hai bisogno.Sono sicuro che qualcuno abbia un esempio in cui è necessario un codice non sicuro, ma nella pratica sembra raro: questo è piuttosto il punto, non è vero?:)

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