如何将字节数组解析为对象?

roz*_*zon 5 .net c#

我正在读取几年前预定义的二进制数据(通过网络流或文件).我目前通过将其读入字节数组然后将数组转换为我需要的字段来读取此数据System.BitConverter.不用说,这是耗费时间和容易出错的.

我希望我可以使用ISerializable,但我不知道如何为预定义的结构实现这一点.

我希望能指出如何改进我目前的战略......

Lar*_*ryF 5

Rozon,我遇到了同样的问题,我就要放弃解决方案,直到我在这里找到这个问题,然后阅读Joe对它的回应.Joe提到Marshal对象在常规MEMORY和一个托管对象之间移动数据......这就是我所做的,以及对我来说有什么作用的魔法......如果你还没有想到这一点,这里有一个完整的突破 -我做了什么,以及如何让它工作..(谢谢乔!)...

首先,您必须能够创建结构的托管实例.这不应该太难,它只是意味着你的结构有很多额外的属性.

例如,这是一个包含有关服务器的一些信息的数据结构.当然,字符串大小不准确,所以请确保你的字符串大小是多少!

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)]
struct TServerInformation {
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=255)]
    public string ComputerName;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=255)]
    public string HostName;

    [MarshalAs(UnmanagedType.U4)]
    public Int32 IPAddress;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=64)]
    public string AdminName;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)]
    public string WindowsDir;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=255)]
    public string Domain;
};
Run Code Online (Sandbox Code Playgroud)

另外,如果您正在使用正确的Charset,在编译为使用Unicode的情况下,您需要确保Charset反映了这一点.

现在,这是很酷的部分......

要获取结构的SIZE(以及需要保存它的缓冲区的大小),您只需要使用:

byte[] buff = new byte[Marshal.SizeOf(pStruct)];
Run Code Online (Sandbox Code Playgroud)

而且,有了这个,你现在可以做任何你做的事情来获取传递给你的这些数据(我假设你已经找到了所有这些...)然后魔术就可以开始了.我们所做的是分配一块非托管内存,然后将缓冲区复制到内存块中,然后将其复制回我们的结构中,并释放非托管内存块.这可以很容易地放入一个可以在任何byte []上运行的扩展函数,使你能够调用类似的东西:

pStruct = (TServerInformation)buff.FromMemory();
Run Code Online (Sandbox Code Playgroud)

以下代码对我有用.哦,不要忘记在生产代码中放置try/catch/finally块...

// Create our Managed Object...
TServerInformation pStruct = new TServerInformation();
// Allocate our block of unmanaged memory...
IntPtr pMem = Marshal.AllocHGlobal(Marshal.SizeOf(pStruct));
// Copy our buff buffer into that new block of memory...
Marshal.Copy(buff, 0, pMem, buff.Length);
// Type-cast that block of memory with the results of the Marshal object's help...
pStruct = (TServerInformation)Marshal.PtrToStructure(pMem, pStruct.GetType());
// Free that block of memory, that is no longer needed now that the data exists in managed form.
Marshal.FreeHGlobal(pMem);
Run Code Online (Sandbox Code Playgroud)

你有它!这避免了使用序列化时包含的所有额外标题信息,并且,这是我发现从托管结构中获取准确"sizeof()"数据的唯一方法.我确信可能有其他方法可以做到这一点,但到目前为止,这是我发现的最好的,经过大约5天的搜索,黑客攻击,搜索,调试,黑客攻击和搜索更多...... :)

如果这对你有用,请告诉我......我很想知道它是否能解决你的问题.


Joe*_*Joe 2

Marshal 互操作类和方法(即 PtrToStruct 和 StructToPtr)也可以提供帮助。请参阅:http ://msdn.microsoft.com/en-us/library/4ca6d5z7.aspx