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