получение байтового представления структуры Int / short / byte с помощью C # - PullRequest
2 голосов
/ 22 октября 2008

Учитывая объект FieldInfo и объект, мне нужно получить фактическое представление поля в байтах. Я знаю, что поле либо int,Int32,uint,short и т. Д.

Как я могу получить фактическое представление байтов? BinaryFormatter.Serialize не поможет, поскольку он даст мне больше информации, чем мне нужно (он также записывает имя типа и т. Д.). Класс Marshal, похоже, не имеет возможности использовать байтовый массив (но, может быть, я что-то упустил).

Спасибо

Ответы [ 3 ]

7 голосов
/ 22 октября 2008

Использовать BitConverter.GetBytes ()

Сначала вам нужно преобразовать значение в его собственный тип, а затем использовать BitConverter для получения байтов:

byte[] Bytes;

if (valType == typeof(int))
{
    int intVal = (int) GetFieldValue(....);
    Bytes = BitConverter.GetBytes(intVval);
} 
else if (valType == typeof(long))
{
    int lngVal = (long) GetFieldValue(....);
    Bytes = BitConverter.GetBytes(lngVal);
} else ....
3 голосов
/ 22 октября 2008

Вы также можете попробовать код, подобный следующему, если вам действительно нужно передать структуры в виде байтового массива:

int rawsize = Marshal.SizeOf(value);
byte[] rawdata = new byte[rawsize];
GCHandle handle = GCHandle.Alloc(rawdata, GCHandleType.Pinned);
Marshal.StructureToPtr(value, handle.AddrOfPinnedObject(), false);
handle.Free();

Преобразует данный объект значение в необработанные байтовые массивы. Я взял это из кода, который я ранее написал, и вам может понадобиться адаптировать его к вашим потребностям, чтобы он действительно работал. Я использовал его для связи с некоторым оборудованием с пользовательскими структурами, но оно должно работать и для встроенных типов (в конце концов, это структуры, не так ли?)

Чтобы правильно выровнять элементы структуры, используйте атрибут StructLayout для указания однобайтового выравнивания:

[StructLayout(LayoutKind.Sequential, Pack = 1)]

А затем используйте атрибут MarshalAs по мере необходимости для полей, например для встроенных массивов:

[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
byte[] _state;

Код для получения структуры из байтового массива выглядит примерно так:

public T GetValue<T>()
{
    GCHandle handle = GCHandle.Alloc(RawValue, GCHandleType.Pinned);
    T structure = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), 
                      typeof(T));
    handle.Free();
    return structure;
}

Конечно, вам нужно знать тип, который вы хотите, чтобы это работало.

Обратите внимание, что это не справится с порядком байтов для себя. В моем проекте большинство полей были только одного байта, поэтому это не имело значения, но для нескольких полей, где это было, я просто сделал поля закрытыми и добавил общедоступные свойства, которые позаботятся о порядке байтов ( Jon Skeet's Ссылка от комментария к его ответу может вам помочь, я написал несколько полезных функций для этого, так как мне нужно было всего несколько).

Когда мне это понадобилось, я создал класс Message, в котором будет храниться необработанное значение (отсюда метод GetValue, код вверху на самом деле является телом метода SetValue), и у меня был удобный метод для получения отформатированного значения и т.д.

2 голосов
/ 22 октября 2008

Вы имеете в виду окончательное представление в памяти? BitConverter.GetBytes (с перегрузкой, подходящим образом выбранной отражением) вернет вам a представление байтов, но не обязательно то, что в данный момент находится в памяти.

Возможно, если вы дадите больше информации о том, почему вы этого хотите, мы сможем вам лучше помочь.

РЕДАКТИРОВАТЬ: я должен добавить, что в любом разумном случае, о котором я могу подумать, BitConverter будет давать вам то же представление, что и в памяти - но могут быть странные ситуации, связанные с порядком байтов и странными архитектурами с различными плавающими точечные представления, которые могут дать странные результаты.

РЕДАКТИРОВАТЬ: Вот полный пример программы, демонстрирующей, как вы могли бы сделать это:

using System;
using System.Reflection;

public class Test
{
    public int x = 300;

    static void Main()
    {
        Test instance = new Test();
        FieldInfo field = typeof(Test).GetField("x");

        MethodInfo converter = typeof(BitConverter).GetMethod("GetBytes", 
            new Type[] {field.FieldType});

        if (converter == null)
        {
            Console.WriteLine("No BitConverter.GetBytes method found for type "
                + field.FieldType);            
        }
        else
        {
            byte[] bytes = (byte[]) converter.Invoke(null,
                new object[] {field.GetValue(instance) });
            Console.WriteLine("Byte array: {0}", BitConverter.ToString(bytes));
        }        
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...