为什么我返回的对象与我收到的对象不匹配?

时间:2015-10-26 14:22:34

标签: c# deserialization pass-by-reference

我正在尝试将字节数组反序列化为结构。

这是我的反序列化功能:

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对象

2 个答案:

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