Pregunta

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

Considere este código...

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

comparado con simplemente usar...

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

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

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

¿Fue útil?

Solución

Es útil para la interoperabilidad con código no administrado.Cualquier puntero pasado a funciones no administradas debe corregirse (también conocido como.anclado) para evitar que el recolector de basura reubique la memoria subyacente.

Si está utilizando P/Invoke, el analizador predeterminado fijará los objetos por usted.A veces es necesario realizar una clasificación personalizada y, a veces, es necesario fijar un objeto durante más tiempo que la duración de una única llamada P/Invoke.

Otros consejos

He usado 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 utilizan normalmente cuando se realiza interoperabilidad o cuando se requiere rendimiento adicional.Es decir.String.CopyTo() utiliza inseguro y fijo en su implementación.

comportamiento de estilo reinterpret_cast

Si eres un poco manipulador, esto puede ser increíblemente útil.

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

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

tenga en cuenta que el nombre se basa en el BitConverter.DoubleToInt64Bits

Continuando con el tema hash, convertir una estructura basada en pila en un byte* permite un 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);
}

Unsafe también (desde 2.0 en adelante) te permite usar stackalloc.Esto puede resultar muy útil en situaciones de alto rendimiento en las que se necesita una pequeña matriz de longitud variable, como espacio temporal.

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

fix es necesario cuando desea interoperar con alguna función útil no administrada (hay muchas) que toma matrices o cadenas de estilo C.Como tal, no es solo por razones de rendimiento sino también de corrección en escenarios de interoperabilidad.

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

Tuvimos que usar una solución fija cuando se pasa una dirección a una DLL C heredada.Dado que la DLL mantenía un puntero interno a través de las llamadas a funciones, se desataría un infierno si el GC compactara el montón y moviera las cosas.

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

Esto me dice que los diseñadores del marco .NET hicieron un buen trabajo al cubrir el espacio del problema, al asegurarse de que el entorno de "código administrado" pueda hacer todo lo tradicional (por ejemplo,C++) puede funcionar con su código/punteros inseguros.En caso de que no sea posible, las funciones inseguras/fijas están ahí si las necesita.Estoy seguro de que alguien tiene un ejemplo en el que se necesita código inseguro, pero parece poco común en la práctica, lo cual es más bien el punto, ¿no?:)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top