gpt4 book ai didi

C#编码问题

转载 作者:行者123 更新时间:2023-11-30 22:36:23 25 4
gpt4 key购买 nike

根据 svick 的建议,我相信我可以大大简化我的帖子和问题。下面是一些完整的代码,它们演示了我的问题和问题,即将字节编码到结构并没有像我期望的那样工作...... 如果对象的两个数组由另一个基元分隔,我的对象没有按照我期望的方式编码为字节。虽然我指定了“Sequential”,但两个 byte[] 数组首先放在字节数组中,然后是 uint。发生了什么事? 在“现实生活”中,我正在处理来自其他人的二进制文件,其中数据的顺序实际上是 byte[5] firstArray、uint firmwareVersion、byte[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;
}




}

最佳答案

如果你在程序集上运行 ildasm.exe 那么问题的原因就很清楚了:

enter image description here

注意神秘<FirmwareRevision>k__BackingField添加到类中的字段。您大概可以猜到它的来源,它是自动属性 ​​FirmwareRevision 的自动生成的支持字段。 native 代码看到的是字段,而不是属性。这使它们的顺序错误。

修复很简单,您需要显式声明支持字段并避免让编译器生成它:

[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..
}

注意 Pack = 1,它通常不正确。在这种情况下它很重要,因为第一个字段有 5 个字节长。自然对齐将 firmwareRevision 放在偏移量 8 处,您将在偏移量 5 处得到它。

关于C#编码问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7044458/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com