Как преобразовать массив значений структуры в байты? - PullRequest
2 голосов
/ 15 декабря 2011

У меня есть System.Array структурных типов значений, что-то вроде этого:

public value struct Position
{
    int timestamp;
    float x;
    float y;
}

Position[] positions = new Position[1000 * 1000];

После того, как я инициализирую массив значениями, как я могу получить byte[] его содержимого, не сериализовав его?элемент за раз?

В C ++ / CLI я бы использовал pin_ptr, чтобы получить указатель на содержимое массива, и я бы скопировал данные оттуда.Могу ли я сделать что-то подобное в C #?

РЕДАКТИРОВАТЬ: мне нужно записать необработанные данные на диск, как если бы это была структура C, без какой-либо сериализации.

Я отметил этовопрос как C # для более широкого представления, но на самом деле я пытаюсь сериализовать данные из IronPython, так что это означает, что я не могу использовать любую unsafe C # функциональность.

Ответы [ 3 ]

2 голосов
/ 15 декабря 2011

Может быть, это поможет:

[Serializable()]
    public struct Position
    {
        int timestamp;
        float x;
        float y;
    }


    static void Main(string[] args)
    {
        var positions = new Position[1000 * 1000];
        GetBytes(positions);
    }
    private static byte[] GetBytes(object obj)
    {
        using (var memoryStream = new System.IO.MemoryStream())
        {
            var binaryFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
            binaryFormatter.Serialize(memoryStream, obj);
            return memoryStream.ToArray();
        }
    }
1 голос
/ 15 декабря 2011

Вот метод, который не требует небезопасного кода:

[Обновлено для удаления цикла for и выполнения копирования за один проход]

private static byte[] StructureToByteArray(Position[] posArray)
{
    if (posArray == null || posArray.Length == 0)
    {
        return new byte[0];
    }

    var lenOfObject = Marshal.SizeOf(typeof(Position));
    var len = lenOfObject * posArray.Length;
    var arr = new byte[len];

    var handle = GCHandle.Alloc(posArray, GCHandleType.Pinned);
    try
    {
        var ptr = handle.AddrOfPinnedObject();
        Marshal.Copy(ptr, arr, 0, len);
    }
    finally
    {
        handle.Free();
    }

    return arr;
}
1 голос
/ 15 декабря 2011

Я считаю, что это эквивалент C ++ / CLI pin_ptr с использованием небезопасного кода C #:

    public static unsafe byte[] GetBytes(Position[] positions)
    {
        byte[] result = new byte[positions.Length * Marshal.SizeOf(typeof(Position))];
        fixed (Position* ptr = &positions[0])
        {
            Marshal.Copy((IntPtr)ptr, result, 0, result.Length);
        }
        return result;
    }
...