2

给定一个 FieldInfo 对象和一个对象,我需要获取该字段的实际字节表示。我知道该领域是要么int,Int32,uint,short等。

如何获得实际的字节表示?BinaryFormatter.Serialize 无济于事,因为它会给我提供比我需要的更多的信息(它还记录类型名称等)。该类Marshal似乎没有使用字节数组的设施(但也许我遗漏了一些东西)。

谢谢

4

3 回答 3

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 ....
于 2008-10-22T13:32:08.370 回答
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 的链接来自对他的回答发表评论可能会对您有所帮助,我为此编写了一些实用程序函数,因为我只需要很少)。

当我需要这个时,我创建了一个 Message 类来存储原始值(因此 GetValue 方法,顶部的代码实际上是 SetValue 方法的主体)并有一些很好的方便方法来获取格式化的值等。

于 2008-10-22T13:41:06.760 回答
2

你的意思是最终的内存表示吗?BitConverter.GetBytes (with an overload suitably chosen by reflection) will return you a byte representation, but not necessarily what it is currently in memory.

也许如果您提供更多关于您为什么想要这个的信息,我们将能够更好地为您提供帮助。

编辑:我应该补充一点,在我能想到的任何合理情况下,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));
        }        
    }
}
于 2008-10-22T13:32:53.873 回答