получение байтового представления Int / short / byte structure с помощью C#
-
03-07-2019 - |
Вопрос
Учитывая объект 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));
}
}
}