将字节数组转换为对象

本文关键字:对象 转换 数组 字节 字节数 | 更新日期: 2023-09-27 18:22:08

C#中有没有将纯字节数组转换为对象的方法?

例如,给定此类:

class Data
{
    public int _int1;
    public int _int2;
    public short _short1;
    public long _long1;
}

我想基本上能够做这样的事情:

var bytes = new byte[] { 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 4, 0, 0, 0, 0, 0, 0, 0 };
var obj = (Data)bytes;

将字节数组转换为对象

您可以尝试编组:

将类的布局声明为Sequential(并注意您需要使用Pack = 1):

[StructLayout(LayoutKind.Sequential, Pack = 1)]
class Data
{
    public int _int1;
    public int _int2;
    public short _short1;
    public long _long1;
}

将字节封送到Data类的新实例中:

var bytes = new byte[] { 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 4, 0, 0, 0, 0, 0, 0, 0 };
GCHandle gcHandle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
var data = (Data)Marshal.PtrToStructure(gcHandle.AddrOfPinnedObject(), typeof(Data));
gcHandle.Free();
// Now data should contain the correct values.
Console.WriteLine(data._int1);    // Prints 1
Console.WriteLine(data._int2);    // Prints 2
Console.WriteLine(data._short1);  // Prints 3
Console.WriteLine(data._long1);   // Prints 4

为了方便起见,您可以在Data上编写一个静态方法来进行转换:

[StructLayout(LayoutKind.Sequential, Pack = 1)]
class Data
{
    public int _int1;
    public int _int2;
    public short _short1;
    public long _long1;
    public static Data FromBytes(byte[] bytes)
    {
        GCHandle gcHandle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
        var data = (Data)Marshal.PtrToStructure(gcHandle.AddrOfPinnedObject(), typeof(Data));
        gcHandle.Free();
        return data;
    }
}
...
var data = Data.FromBytes(new byte[] {1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 4, 0, 0, 0, 0, 0, 0, 0});

如果你真的想的话,你可以写一个显式运算符来从字节数组转换,以在你的OP中获得语法。我建议只使用Data.FromBytes(),这将是一个更清晰的IMO.

不过,只是为了完整性:

[StructLayout(LayoutKind.Sequential, Pack = 1)]
class Data
{
    public int _int1;
    public int _int2;
    public short _short1;
    public long _long1;
    public static explicit operator Data(byte[] bytes)
    { 
        GCHandle gcHandle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
        var data = (Data)Marshal.PtrToStructure(gcHandle.AddrOfPinnedObject(), typeof(Data));
        gcHandle.Free();
        return data;
    }
}
...
var data = (Data)new byte[] {1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 4, 0, 0, 0, 0, 0, 0, 0};

使用BitConverter.ToInt32/Int16/Int64方法。您只需指定起始索引,如:

Data data = new Data();
data._int1 = BitConverter.ToInt32(bytes, 0);
data._int2 = BitConverter.ToInt32(bytes, 4);
data._short1 = BitConverter.ToInt16(bytes, 8);
data._long1 = BitConverter.ToInt64(bytes,10);

请记住:

BitConverter.ToInt32

数组中的字节顺序必须反映计算机系统体系结构;

这里有一种将字节数组转换为对象的方法。

var binaryFormatter = new BinaryFormatter();
using (var ms = new MemoryStream(bytes))
{
    object obj = binaryFormatter.Deserialize(ms);
    return (Data)obj;
}

没有什么能一次完成转换。

但您可以在BitConverter:之上进行构建

var d = new Data();
var sI32 = sizeof(Int32);
d._int1 = BitConverter.ToInt32(bytes, 0);
d._int2 = BitConverter.ToInt32(bytes, sI32);
d._short1 = BitConverter.ToInt16(bytes, 2*sI32);
…