2008-10-22 3 views
2

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

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

Благодаря

ответ

3

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

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; 
} 

Конечно, вы должны знать тип, который вы хотите для этого работы ,

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

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

7

Использование 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 .... 
+0

Nah, сделайте это с отражением :) – 2008-10-22 13:39:38

2

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

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

EDIT: Я хотел бы добавить, что в любом разумном случае я могу думать, BitConverter будет дать вам такое же представление, как и в памяти - но может быть нечетным ситуации, связанные с порядком байтов и, возможно, странные архитектуры с различными точками представлений плавающими, которые может дать странные результаты.

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

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

Я тоже собирался опубликовать его, но похоже, что GetBytes не имеет перегрузки, которая принимает объект, то есть все равно придется писать код, который преобразуется в подходящий тип. Или я что-то пропустил? – OregonGhost 2008-10-22 13:34:44

+0

Нет, вы ничего не пропустили - вам нужно будет выработать метод вызова. Достаточно легко сделать - я отредактирую с образцом кода. – 2008-10-22 13:35:35

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