2011-12-15 2 views
2

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

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

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

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

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

EDIT: Мне нужно записать необработанные данные на диск, как если бы это была структура C, без какой-либо сериализации.

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

+1

Не работает 'Convert.GetBytes()'? – Default

+0

Дубликат: http://stackoverflow.com/questions/1068541/how-to-convert-a-value-type-to-byte-in-c – Kugel

+0

@Default: если вы имеете в виду «BitConverter.GetBytes», нет , он не работает. Он возвращает 'byte []' с одним байтом внутри – Meh

ответ

1

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

[Обновлено, чтобы удалить цикл 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; 
} 
+0

Тот же вопрос, что и при небезопасном ответе: было бы неплохо применить атрибут 'StructLayout' с' LayoutKind' либо 'Sequential', либо' Explicit' к структуре 'Position', если вы используете этот подход или делает это не важно? –

+0

Было бы неплохо указать 'LayoutKind.Sequential'. Поскольку структуры часто используются для взаимодействия, это по умолчанию для компиляторов C#/VB.NET (и, возможно, других), но нет никакой гарантии, что это останется верным. –

+0

Это проходит через каждый элемент. Я хочу этого избежать. – Meh

2

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

[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(); 
     } 
    } 
+0

Я не думаю, что форматы Serialization возвращают необработанные данные. – Meh

+0

Этот подход дает массив байтов, и для этого требуется очень мало усилий по кодированию, поэтому я считаю, что это вполне правильный ответ. Разумеется, результирующий массив байтов не будет настолько малым, насколько это возможно, потому что он содержит некоторую информацию о типе, которая используется для десериализации. Человек должен решить, подходит ли это их потребностям. –

+0

Я просто думаю, что использование стандартного пакета i C# лучше, чем использование небезопасного кода. Я также думаю, что это правда, что при сериализации объекта он должен сохранять информацию о типе. Таким образом, массив байтов может быть больше, но стандартное решение, по-моему, более предпочтительное. – Arion

1

Я считаю, что это эквивалентно 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; 
    } 
+0

Нужно ли применять атрибут StructLayout с помощью LayoutKind либо Sequential, либо Explicit к структуре Position, чтобы надежно использовать этот подход? Просто интересуюсь. –

+0

Спасибо, но я не могу использовать небезопасные. Я почему-то обновил описание. – Meh

+0

@Dr. Ученик Уайли, я бы определенно рекомендовал использовать Явный макет, если вы попытаетесь взаимодействовать с неуправляемым кодом, ожидающим определенный бинарный макет.Я не уверен, насколько сильны гарантии для автоматического позиционирования макета. –

Смежные вопросы