C# unsafe value type array to byte array conversions

后端 未结 7 814
梦毁少年i
梦毁少年i 2020-11-30 08:20

I use an extension method to convert float arrays into byte arrays:

public static unsafe byte[] ToByteArray(this float[] floatArray, int count)
{
    int arr         


        
7条回答
  •  醉话见心
    2020-11-30 08:47

    You can use a really ugly hack to temporary change your array to byte[] using memory manipulation.

    This is really fast and efficient as it doesn't require cloning the data and iterating on it.

    I tested this hack in both 32 & 64 bit OS, so it should be portable.

    The source + sample usage is maintained at https://gist.github.com/1050703 , but for your convenience I'll paste it here as well:

    public static unsafe class FastArraySerializer
    {
        [StructLayout(LayoutKind.Explicit)]
        private struct Union
        {
            [FieldOffset(0)] public byte[] bytes;
            [FieldOffset(0)] public float[] floats;
        }
    
        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        private struct ArrayHeader
        {
            public UIntPtr type;
            public UIntPtr length;
        }
    
        private static readonly UIntPtr BYTE_ARRAY_TYPE;
        private static readonly UIntPtr FLOAT_ARRAY_TYPE;
    
        static FastArraySerializer()
        {
            fixed (void* pBytes = new byte[1])
            fixed (void* pFloats = new float[1])
            {
                BYTE_ARRAY_TYPE = getHeader(pBytes)->type;
                FLOAT_ARRAY_TYPE = getHeader(pFloats)->type;
            }
        }
    
        public static void AsByteArray(this float[] floats, Action action)
        {
            if (floats.handleNullOrEmptyArray(action)) 
                return;
    
            var union = new Union {floats = floats};
            union.floats.toByteArray();
            try
            {
                action(union.bytes);
            }
            finally
            {
                union.bytes.toFloatArray();
            }
        }
    
        public static void AsFloatArray(this byte[] bytes, Action action)
        {
            if (bytes.handleNullOrEmptyArray(action)) 
                return;
    
            var union = new Union {bytes = bytes};
            union.bytes.toFloatArray();
            try
            {
                action(union.floats);
            }
            finally
            {
                union.floats.toByteArray();
            }
        }
    
        public static bool handleNullOrEmptyArray(this TSrc[] array, Action action)
        {
            if (array == null)
            {
                action(null);
                return true;
            }
    
            if (array.Length == 0)
            {
                action(new TDst[0]);
                return true;
            }
    
            return false;
        }
    
        private static ArrayHeader* getHeader(void* pBytes)
        {
            return (ArrayHeader*)pBytes - 1;
        }
    
        private static void toFloatArray(this byte[] bytes)
        {
            fixed (void* pArray = bytes)
            {
                var pHeader = getHeader(pArray);
    
                pHeader->type = FLOAT_ARRAY_TYPE;
                pHeader->length = (UIntPtr)(bytes.Length / sizeof(float));
            }
        }
    
        private static void toByteArray(this float[] floats)
        {
            fixed(void* pArray = floats)
            {
                var pHeader = getHeader(pArray);
    
                pHeader->type = BYTE_ARRAY_TYPE;
                pHeader->length = (UIntPtr)(floats.Length * sizeof(float));
            }
        }
    }
    

    And the usage is:

    var floats = new float[] {0, 1, 0, 1};
    floats.AsByteArray(bytes =>
    {
        foreach (var b in bytes)
        {
            Console.WriteLine(b);
        }
    });
    

提交回复
热议问题