我正在尝试将字节数组反序列化为结构。
这是我的反序列化功能:
void RawDeserialize(byte[] bytearray, object obj)
{
int len = Marshal.SizeOf(obj);
IntPtr i = Marshal.AllocHGlobal(len);
Marshal.Copy(bytearray, 0, i, len);
obj = Marshal.PtrToStructure(i, obj.GetType());
Marshal.FreeHGlobal(i);
}
我用
打电话RawDeserialize(outarr, outbuf);
其中outarr是一个长度为22的字节数组,outbuf是我的结构,如下所示:
[StructLayout(LayoutKind.Sequential,Size =22)]
public struct ID_OUTPUT
{
public HEADER_OUTPUT hdr; //Another struct size=8
public byte bType;
public byte bRunning;
[MarshalAs(UnmanagedType.ByValTStr,SizeConst = 8)]
public string softwareName;
public short softwareVersion;
}
当我在反序列化函数中逐步调试时, obj 会填充正确的值,但在返回 outbuf 时会填充零(或从未分配给因为我最初将所有内容初始化为零)。
我最初的想法是对象没有通过引用传递,但我认为这应该有效,因为我在另一个SO问题上找到了这个反序列化函数(我没有链接了)。
然后我尝试使用 ref 关键字,但后来我收到错误无法从ref ID_OUTPUT转换为ref对象。
答案 0 :(得分:3)
您正在将局部变量obj
的引用重新定义为与传递给方法不同的内容。调用方法中的实际引用不会改变。当您将方法签名更改为ref
变量时,它确实有效,但是您遇到了转换问题。
由于您的方法是void
,最简单的方法是返回变量并适当地键入它(或者如果需要,可以将其转换)。 (您可以在返回变量上使用泛型,无论哪种方式最适合您)。
必需的方法签名:
ID_OUTPUT /* your struct return variable */ RawDeserialize(byte[] bytearray);
如果问题仅仅是转换问题,则会解决此问题:
ID_OUTPUT obj;
object outputObject = obj;
RawDeserialize(bytearray, ref outputObject);
obj = (ID_OUTPUT)outputObject;
答案 1 :(得分:3)
当您处理多种结构类型并希望使用一种独特的方法来完成工作时,generics是一个不错的选择。这允许您使用漂亮的C#语法,而无需将实例强制转换为object
。
// For .Net 4.5 and previous versions
public static T RawDeserialize<T>(byte[] bytearray)
where T : struct
{
var type = typeof(T);
int len = Marshal.SizeOf(type);
IntPtr i = IntPtr.Zero;
try
{
i = Marshal.AllocHGlobal(len);
Marshal.Copy(bytearray, 0, i, len);
return (T)Marshal.PtrToStructure(i, type);
}
finally
{
if (i != IntPtr.Zero)
{
Marshal.FreeHGlobal(i);
}
}
}
用法:
ID_OUTPUT myStruct = RawDeserialize<ID_OUTPUT>(someByteArray);
ZZZZ myStruct2 = RawDeserialize<ZZZZ>(someByteArray);
对于.Net 4.5.1+,您可能需要使用SizeOf / PtrToStructure的通用版本:
public static T RawDeserialize<T>(byte[] bytearray)
where T : struct
{
int len = Marshal.SizeOf<T>();
IntPtr i = IntPtr.Zero;
try
{
i = Marshal.AllocHGlobal(len);
Marshal.Copy(bytearray, 0, i, len);
return Marshal.PtrToStructure<T>(i);
}
finally
{
if (i != IntPtr.Zero)
{
Marshal.FreeHGlobal(i);
}
}
}