C#编组问题

C#编组问题,c#,marshalling,C#,Marshalling,基于svick的建议,我相信我可以实质上简化我的帖子和问题。下面是一些完整的代码,它演示了我的问题,也就是说,将字节编组到结构并没有按照我预期的方式工作。。。 如果一个对象的两个数组被另一个原语分隔,那么我的对象并没有按照我预期的方式被编组为字节。虽然我指定了“Sequential”,但两个字节[]数组首先放在字节数组中,uint如下。发生了什么事? 在“现实生活”中,我处理的是来自其他人的二进制文件,其中数据的顺序是字节[5]firstArray,uint firmwareVersion,字节

基于svick的建议,我相信我可以实质上简化我的帖子和问题。下面是一些完整的代码,它演示了我的问题,也就是说,将字节编组到结构并没有按照我预期的方式工作。。。 如果一个对象的两个数组被另一个原语分隔,那么我的对象并没有按照我预期的方式被编组为字节。虽然我指定了“Sequential”,但两个字节[]数组首先放在字节数组中,uint如下。发生了什么事? 在“现实生活”中,我处理的是来自其他人的二进制文件,其中数据的顺序是字节[5]firstArray,uint firmwareVersion,字节[9]secondArray

根据要求,我已经给出了一个完整的代码示例和注释

namespace MarshallingExample
{
class Program
{
    static void Main(string[] args)
    {

        // first show that our Marshalling to/from objects to bytes is working ...
        Simple simpleObject = new Simple();
        simpleObject.HeaderInfo = new byte[5] { 1, 2, 3, 4, 5 };
        simpleObject.FirmwareRevision = 1234;
        byte[] simpleObjectBytes = Tools.ConvertObjectToBytes(simpleObject);
        Simple simpleObject2 = Tools.ConvertBytesToObject(simpleObjectBytes, 0, typeof(Simple)) as Simple;

        Complex complexObject = new Complex();
        complexObject.HeaderInfo = new byte[5] { 1, 2, 3, 4, 5 };
        complexObject.FirmwareRevision = 1234;

        complexObject.SoftwarePartNumber = new byte[9] { 11, 12, 13, 14, 15, 16, 17, 18, 19 };
        byte[] complexObjectBytes = Tools.ConvertObjectToBytes(complexObject);   // look at complexObjectBytes!!!
        // Notice that the two arrays come first in complexObjectBytes.  Not a problem here.
        Complex complexObject2 = Tools.ConvertBytesToObject(complexObjectBytes, 0, typeof(Complex)) as Complex;



        // Set up some data in MemoryStream(would really be in files) as it's actually given to us....
        MemoryStream memStreamSimple;
        memStreamSimple = new MemoryStream(9);
        memStreamSimple.Write(simpleObject.HeaderInfo, 0, 5);
        memStreamSimple.Write(BitConverter.GetBytes(simpleObject.FirmwareRevision), 0, 4);

        MemoryStream memStreamComplex;
        memStreamComplex = new MemoryStream(18);
        memStreamComplex.Write(complexObject.HeaderInfo, 0, 5);
        memStreamComplex.Write(BitConverter.GetBytes(complexObject.FirmwareRevision), 0, 4);
        memStreamComplex.Write(complexObject.SoftwarePartNumber, 0, 9);


        // now read and try to put in our structures....

        memStreamSimple.Seek(0, SeekOrigin.Begin);
        simpleObjectBytes = new byte[9];
        int count = memStreamSimple.Read(simpleObjectBytes, 0, 9);
        simpleObject2 = Tools.ConvertBytesToObject(simpleObjectBytes, 0, typeof(Simple)) as Simple;

        memStreamComplex.Seek(0, SeekOrigin.Begin);
        complexObjectBytes = new byte[18];
        count = memStreamComplex.Read(complexObjectBytes, 0, 18);
        // Note that following object is all messed up, probably because it was expecting the two arrays first.
        complexObject2 = Tools.ConvertBytesToObject(complexObjectBytes, 0, typeof(Complex)) as Complex;
    }
}

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class Simple
{
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
    private byte[] _headerInfo = new byte[5];
    public byte[] HeaderInfo
    {
        get
        {
            return _headerInfo;
        }
        set
        {
            _headerInfo = value;
        }
    }

    public uint FirmwareRevision
    {
        get;
        set;
    }


}

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class Complex
{
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
    private byte[] _headerInfo = new byte[5];
    public byte[] HeaderInfo
    {
        get
        {
            return _headerInfo;
        }
        set
        {
            _headerInfo = value;
        }
    }

    public uint FirmwareRevision
    {
        get;
        set;
    }

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 9)]
    private byte[] _softwarePartNumber = new byte[9];
    public byte[] SoftwarePartNumber
    {
        get
        {
            return _softwarePartNumber;
        }
        set
        {
            _softwarePartNumber = value;
        }
    }

}

public static class Tools
{

    /// <summary>
    /// Convert an array of bytes starting at the offset provided into the specified type (struct or class).
    /// </summary>
    /// <param name="bytes"></param>
    /// <param name="startOffset"></param>
    /// <param name="type"></param>
    /// <returns>Newly created object of the specified type created from bytes given. NULL on any error.</returns>
    public static object ConvertBytesToObject(byte[] bytes, int startOffset, Type type)
    {
        object obj = null;
        int size = Marshal.SizeOf(type);

        if (size > 0)
        {
            if (size <= bytes.Length - startOffset)
            {
                IntPtr ptr = IntPtr.Zero;

                try
                {
                    ptr = Marshal.AllocHGlobal(size);
                    Marshal.Copy(bytes, startOffset, ptr, size);
                    obj = Marshal.PtrToStructure(ptr, type);
                }
                finally
                {
                    if (ptr != IntPtr.Zero)
                    {
                        Marshal.FreeHGlobal(ptr);
                    }
                }
            }
            else
            {
                throw new Exception("ConvertBytesToObject: Requested offset + size of object exceeds length of bytes buffer to read.");
            }
        }
        else
        {
            throw new Exception("ConvertBytesToObject: Marshal.SizeOf(T) returned a size of 0.");
        }

        return obj;
    }

    /// <summary>
    /// Convert an object (struct or class) to an array of bytes.
    /// </summary>
    /// <param name="obj"></param>
    /// <returns></returns>
    public static byte[] ConvertObjectToBytes(object obj)
    {
        byte[] bytes = null;

        if (obj != null)
        {
            IntPtr ptr = IntPtr.Zero;
            Type type = obj.GetType();
            int size = Marshal.SizeOf(type);
            //int size = Marshal.SizeOf(obj.GetType());

            if (size > 0)
            {
                try
                {
                    ptr = Marshal.AllocHGlobal(size);
                    if (ptr != IntPtr.Zero)
                    {
                        Marshal.StructureToPtr(obj, ptr, false);
                        bytes = new byte[size];
                        Marshal.Copy(ptr, bytes, 0, size);
                    }
                }
                finally
                {
                    if (ptr != IntPtr.Zero)
                    {
                        Marshal.FreeHGlobal(ptr);
                    }
                }
            }
            else
            {
                throw new Exception("ConvertObjectToBytes: Marshal.SizeOf(T) returned a size of 0.");
            }
        }

        return bytes;
    }




}
名称空间封送示例
{
班级计划
{
静态void Main(字符串[]参数)
{
//首先说明我们将对象编组到字节/从对象编组到字节的工作正常。。。
Simple simpleObject=new Simple();
simpleObject.HeaderInfo=新字节[5]{1,2,3,4,5};
simpleObject.FirmwareRevision=1234;
byte[]simpleObjectBytes=Tools.ConvertObjectToBytes(simpleObject);
Simple simpleObject2=Tools.ConvertByTestObject(simpleObjectBytes,0,typeof(Simple))作为简单对象;
Complex complexObject=新的Complex();
complexObject.HeaderInfo=新字节[5]{1,2,3,4,5};
complexObject.FirmwareRevision=1234;
complexObject.SoftwarePartNumber=新字节[9]{11,12,13,14,15,16,17,18,19};
byte[]complexObjectBytes=Tools.ConvertObjectToBytes(complexObject);//看看complexObjectBytes!!!
//请注意,这两个数组以complexObjectBytes的形式排在第一位,这里没有问题。
complexObject2=Tools.ConvertBytesToObject(complexObjectBytes,0,typeof(Complex))作为复数;
//在MemoryStream中设置一些实际提供给我们的数据(实际上是在文件中)。。。。
MemoryStream memStreamSimple;
memStreamSimple=新的MemoryStream(9);
memStreamSimple.Write(simpleObject.HeaderInfo,0,5);
memStreamSimple.Write(BitConverter.GetBytes(simpleObject.FirmwareRevision),0,4;
MemoryStream Memstream复合物;
memStreamComplex=新的内存流(18);
memStreamComplex.Write(complexObject.HeaderInfo,0,5);
memStreamComplex.Write(位转换器.GetBytes(complexObject.FirmwareRevision),0,4);
memStreamComplex.Write(complexObject.SoftwarePartNumber,0,9);
//现在请阅读并尝试加入我们的结构。。。。
memStreamSimple.Seek(0,SeekOrigin.Begin);
simpleObjectBytes=新字节[9];
int count=memStreamSimple.Read(simpleObjectBytes,0,9);
simpleObject2=Tools.ConvertBytesToObject(simpleObjectBytes,0,typeof(Simple))作为Simple;
memStreamComplex.Seek(0,SeekOrigin.Begin);
complexObjectBytes=新字节[18];
count=memStreamComplex.Read(complexObjectBytes,0,18);
//请注意,下面的对象都搞砸了,可能是因为它希望先有两个数组。
complexObject2=Tools.ConvertBytesToObject(complexObjectBytes,0,typeof(Complex))作为复数;
}
}
[StructLayout(LayoutKind.Sequential,Pack=1)]
公共类简单
{
[Marshallas(UnmanagedType.ByValArray,SizeConst=5)]
专用字节[]_headerInfo=新字节[5];
公共字节[]头信息
{
得到
{
返回头信息;
}
设置
{
_headerInfo=值;
}
}
公共保险公司
{
得到;
设置
}
}
[StructLayout(LayoutKind.Sequential,Pack=1)]
公共类综合体
{
[Marshallas(UnmanagedType.ByValArray,SizeConst=5)]
专用字节[]_headerInfo=新字节[5];
公共字节[]头信息
{
得到
{
返回头信息;
}
设置
{
_headerInfo=值;
}
}
公共保险公司
{
得到;
设置
}
[Marshallas(UnmanagedType.ByValArray,SizeConst=9)]
专用字节[]_softwarePartNumber=新字节[9];
公共字节[]软件部件号
{
得到
{
返回软件零件号;
}
设置
{
_softwarePartNumber=值;
}
}
}
公共静态类工具
{
/// 
///将从提供的偏移量开始的字节数组转换为指定的类型(结构或类)。
/// 
/// 
/// 
/// 
///根据给定字节创建的指定类型的新创建对象。出现任何错误时为空。
公共静态对象ConvertBytesToObject(字节[]字节,int startOffset,类型)
{
objectobj=null;
int size=Marshal.SizeOf(类型);
如果(大小>0)
{
如果(尺寸0)
{
尝试
{
ptr=Marshal.AllocHGlobal(大小);
如果(ptr!=IntPtr.Zero)
{
Marshal.StructureToPtr(obj、ptr、false);
字节=新字节[大小];
封送处理副本(ptr,字节,0,大小);
}
}
最后
{
如果(ptr!=IntPtr.Zero)
{
弗里赫全球元帅(ptr);
}
}
}
其他的
{
抛出新异常(“ConvertObjectToBytes:Marshal.SizeOf(T)返回的大小为0”);
}
}
返回字节;
}
}

}

如果在程序集上运行ildasm.exe,则问题的原因将变得很清楚:

注意添加到类中的神秘的
k_ubackingfield
字段。您可能可以猜测它来自何处,它是自动属性FirmwareRevision的自动生成的支持字段。n
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class Complex {
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
    private byte[] _headerInfo = new byte[5];
    private uint firmwareRevision;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 9)]
    private byte[] _softwarePartNumber = new byte[9];

    public uint FirmwareRevision {
        get { return firmwareRevision; }
        set { firmwareRevision = value; }
    }
    //etc..
}