C# 使用C获取Int/short/byte结构字节表示#

C# 使用C获取Int/short/byte结构字节表示#,c#,reflection,marshalling,binary-data,C#,Reflection,Marshalling,Binary Data,给定一个FieldInfo对象和一个object,我需要得到字段的实际字节表示形式。我知道该字段是int、Int32、uint、short等 如何获得实际的字节表示?Serialize不会有帮助,因为它会给我比我需要的更多的信息(它还记录类型名等)。Marshal类似乎没有使用字节数组的工具(但可能我遗漏了一些东西) 感谢使用BitConverter.GetBytes() 首先必须将值转换为其本机类型,然后使用位转换器获取字节: byte[] Bytes; if (valType == typ

给定一个FieldInfo对象和一个object,我需要得到字段的实际字节表示形式。我知道该字段是
int、Int32、uint、short等

如何获得实际的字节表示?Serialize不会有帮助,因为它会给我比我需要的更多的信息(它还记录类型名等)。
Marshal
类似乎没有使用字节数组的工具(但可能我遗漏了一些东西)

感谢使用BitConverter.GetBytes()

首先必须将值转换为其本机类型,然后使用位转换器获取字节:

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(通过反射适当选择重载)将返回字节表示形式,但不一定返回内存中当前的字节表示形式

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

编辑:我应该补充一点,在我能想到的任何合理的情况下,BitConverter都会给您提供与内存中相同的表示形式——但是可能会有一些奇怪的情况,包括endianness和可能具有不同浮点表示形式的奇怪架构,这可能会产生奇怪的结果

编辑:下面是一个完整的示例程序,演示了如何进行:

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

如果您真正想要的是将结构作为字节数组传输,您也可以尝试以下代码:

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;
}
public T GetValue()
{
GCHandle handle=GCHandle.Alloc(原始值,GCHandleType.pinted);
T structure=(T)Marshal.PtrToStructure(handle.addrofPindedObject(),
(T)型;
handle.Free();
回报结构;
}
当然,您需要知道要使其工作的类型

请注意,这不会自行处理endianness。在我的项目中,大多数字段只有一个字节,所以这无关紧要,但对于有字节的少数字段,我只是将字段设置为私有字段,并添加了公共属性,以处理endianness(从一条评论到他的答案可能会帮到你,我为此编写了一些实用函数,因为我只需要几个)


当我需要它时,我创建了一个消息类来存储原始值(因此是GetValue方法,顶部的代码实际上是SetValue方法的主体),并使用了一些非常方便的方法来格式化值等。

我也准备发布它,但GetBytes似乎没有接受对象的重载,也就是说,仍然需要先编写转换为适当类型的代码。或者我遗漏了什么?不,你没有遗漏任何东西-你必须找出调用的方法。不过很容易做到——我将使用代码示例进行编辑。我正在尝试将我的对象序列化为硬件所需的特定格式。我有一个消息对象,我用该对象拥有的特殊方法序列化它。它看起来像:
class msg:mbase{uint x;}
mbase移动msg的所有字段并序列化它们。当然,理想情况下,我想要控制endianness,即getBigEndianBytes()。如果您想要控制endianness,请使用Nah中的EndianBitConverter,使用反射:)谢谢,这更像我想要的。您如何确保结构按照您希望的方式对齐?