получение байтового представления Int / short / byte structure с помощью C#

StackOverflow https://stackoverflow.com/questions/225717

Вопрос

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

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

Спасибо

Это было полезно?

Решение

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

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();

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

Чтобы элементы структуры были правильно выровнены, используйте атрибут 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;
}

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

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

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

Другие советы

Используйте 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 ....

Вы имеете в виду окончательное представление в памяти?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));
        }        
    }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top