remarks example cref code c# .net unsafe fixed

example - C#Código inseguro/fijo



params comments c# (7)

¿Alguien puede dar un ejemplo de un buen momento para usar realmente "inseguro" y "fijo" en el código C #? He jugado con él antes, pero en realidad nunca encontré un buen uso para él.

Considera este código ...

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

en comparación con simplemente usar ...

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

El segundo es el código que se encuentra en .NET Framework, el primero es una parte del código copiado del sitio web de Microsoft, http://msdn.microsoft.com/en-us/library/28k1s2k6(VS.80).aspx .

El built-in Array.Copy () es mucho más rápido que el uso de código inseguro. Esto podría ser solo porque el segundo está mejor escrito y el primero es solo un ejemplo, pero ¿qué tipo de situaciones necesitarías para usar código inseguro / fijo para algo? ¿O es este pobre desarrollador web jugando con algo por encima de su cabeza?


Creo que se usa un código inseguro si desea acceder a algo que esté fuera del tiempo de ejecución de .NET, es decir. no es código administrado (no hay recolección de basura, etc.). Esto incluye llamadas en bruto a la API de Windows y todo ese jazz.


Es útil para la interoperabilidad con código no administrado. Todos los punteros pasados ​​a funciones no administradas deben ser reparados (también llamados fijados) para evitar que el recolector de basura reubique la memoria subyacente.

Si está utilizando P / Invoke, el Marshaller predeterminado fijará objetos por usted. A veces es necesario realizar una clasificación personalizada, y en ocasiones es necesario fijar un objeto por más tiempo que la duración de una sola llamada P / Invoke.


Esto me dice que los diseñadores de .NET Framework hicieron un buen trabajo cubriendo el espacio problemático, de asegurarse de que el entorno de "código administrado" pueda hacer todo lo que un enfoque tradicional (por ejemplo C ++) puede hacer con sus códigos / punteros inseguros. En caso de que no pueda, las características inseguras / fijas están ahí si las necesita. Estoy seguro de que alguien tiene un ejemplo donde se necesita un código inseguro, pero parece raro en la práctica, que es más bien el punto, ¿no es así? :)


He utilizado bloques inseguros para manipular datos de mapa de bits. El acceso al puntero sin formato es significativamente más rápido que SetPixel / GetPixel.

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

"fijo" e "inseguro" se usa normalmente cuando se hace interoperabilidad, o cuando se requiere un rendimiento adicional. Es decir. String.CopyTo () usa inseguro y está fijo en su implementación.


Inseguro es útil para (por ejemplo) obtener datos de píxeles de una imagen rápidamente usando LockBits. La mejora del rendimiento sobre hacer esto utilizando la API administrada es de varios órdenes de magnitud.


Tuvimos que usar un arreglo cuando una dirección pasa a una DLL de C heredada. Dado que el DLL mantenía un puntero interno a través de llamadas a funciones, todo el infierno se desataría si GC compactaba el montón y movía cosas.


reinterpretar el comportamiento del estilo de difusión

Si manipulas un poco, esto puede ser increíblemente útil

muchas implementaciones de código de hash de alto rendimiento usan UInt32 para el valor hash (esto simplifica los cambios). Dado que .Net requiere Int32 para el método que desea convertir rápidamente el uint a un int. Como no importa cuál sea el valor real, solo se preservan todos los bits del valor, se desea un reinterpreteo.

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

tenga en cuenta que la nomenclatura se modela en BitConverter.DoubleToInt64Bits

Continuando en la veta hash, la conversión de una estructura basada en pila en un byte * permite el uso fácil de las funciones hash por 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); }

inseguro también (de 2.0 en adelante) le permite usar stackalloc. Esto puede ser muy útil en situaciones de alto rendimiento donde se necesita una pequeña variedad de longitud variable como espacio temporal.

Todos estos usos estarían firmemente en "solo si su aplicación realmente necesita el rendimiento" y, por lo tanto, son inapropiados en el uso general, pero a veces realmente lo necesitan.

fixed es necesario para cuando desea interoperar con alguna función útil no administrada (hay muchas) que toma arreglos o cadenas estilo c. Como tal, no es solo por razones de rendimiento sino de corrección cuando se trata de escenarios de interoperabilidad.