【发布时间】:2020-03-18 01:36:31
【问题描述】:
我希望将字节数组重新解释为 C# 结构。我已经阅读了该问题的其他几个答案,大多数都是关于如何实现重新解释演员表。我已经确定了一种重新解释演员表的方法,但是在我的演员表中我得到的是单个字符而不是字符数组。
例如,我有以下对象:
public unsafe struct Establish503
{
public static Establish503 ReinterpretCast(byte[] message)
{
GCHandle handle = GCHandle.Alloc(message, GCHandleType.Pinned);
Establish503 theStruct = (Establish503)Marshal.PtrToStructure(handle.AddrOfPinnedObject(),
typeof(Establish503));
handle.Free();
return theStruct;
}
public fixed char HMACSignature[32];
public fixed char AccessKey[20];
public fixed char TradingSystemName[30];
public fixed char TradingSystemVersion[10];
public fixed char TradingSystemVendor[10];
}
由于某种原因,我没有一个字节数组,而是在一个数组应该有的地方有单个字符。为什么会这样?这是我的本地调试窗口:
如您所见,出于某种原因,它将所有字段视为char 而不是char[]。
如果这不是正确的方法,我还有什么需要注意的吗?我一直在调查Span<T>。
编辑:在与所选答案的作者 Oguz Ozgul 进一步讨论后,确定编组是最好的方法。一个后续问题是,我将如何处理嵌套结构?以下是我目前的做法。正如 Oguz 所提到的,对于在类之外定义且包含原始类型的结构,可以排除 Marshal 属性。然后这些结构可以用作另一个结构中的字段。我已经解决了定义嵌套结构的问题,类似于我定义非嵌套结构的方式。
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct OrderMassActionReport558
{
public const int templateId_ = 558;
public const int blockSize_ = 103;
public static OrderMassActionReport558 ReinterpretCast(byte[] message)
{
GCHandle handle = GCHandle.Alloc(message, GCHandleType.Pinned);
OrderMassActionReport558 theStruct = (OrderMassActionReport558)
Marshal.PtrToStructure(handle.AddrOfPinnedObject(),
typeof(OrderMassActionReport558));
handle.Free();
return theStruct;
}
[MarshalAs(UnmanagedType.U4)]
public uInt32 seqNum;
[MarshalAs(UnmanagedType.U8)]
public uInt64 uUID;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
private byte[] _senderID;
public string senderID => System.Text.Encoding.ASCII.GetString(this._senderID);
[MarshalAs(UnmanagedType.U8)]
public uInt64 partyDetailsListReqID;
[MarshalAs(UnmanagedType.U8)]
public uInt64 transactTime;
[MarshalAs(UnmanagedType.U8)]
public uInt64 sendingTimeEpoch;
[MarshalAs(UnmanagedType.U8)]
public uInt64 orderRequestID;
[MarshalAs(UnmanagedType.U8)]
public uInt64 massActionReportID;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
private byte[] _securityGroup;
public string securityGroup => System.Text.Encoding.ASCII.GetString(this._securityGroup);
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
private byte[] _location;
public string location => System.Text.Encoding.ASCII.GetString(this._location);
[MarshalAs(UnmanagedType.I4)]
public Int32NULL securityID;
[MarshalAs(UnmanagedType.U2)]
public uInt16NULL delayDuration;
[MarshalAs(UnmanagedType.U1)]
public MassActionResponse massActionResponse;
[MarshalAs(UnmanagedType.U1)]
public ManualOrdIndReq manualOrderIndicator;
[MarshalAs(UnmanagedType.U1)]
public MassActionScope massActionScope;
[MarshalAs(UnmanagedType.U1)]
public uInt8 totalAffectedOrders;
[MarshalAs(UnmanagedType.U1)]
public BooleanFlag lastFragment;
[MarshalAs(UnmanagedType.U1)]
public uInt8NULL massActionRejectReason;
[MarshalAs(UnmanagedType.U1)]
public uInt8NULL marketSegmentID;
[MarshalAs(UnmanagedType.U1)]
public MassCxlReqTyp massCancelRequestType;
[MarshalAs(UnmanagedType.U1)]
public SideNULL side;
[MarshalAs(UnmanagedType.U1)]
public MassActionOrdTyp ordType;
[MarshalAs(UnmanagedType.U1)]
public MassCancelTIF timeInForce;
[MarshalAs(UnmanagedType.U1)]
public SplitMsg splitMsg;
[MarshalAs(UnmanagedType.U1)]
public BooleanNULL liquidityFlag;
[MarshalAs(UnmanagedType.U1)]
public BooleanFlag possRetransFlag;
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct NoAffectedOrdersEntry
{
public const int blockSize_ = 32;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
private byte[] _origCIOrdID;
public string origCIOrdID => System.Text.Encoding.ASCII.GetString(this._origCIOrdID);
public uInt64 AffectedOrderID;
public uInt32 CxlQuantity;
}
}
【问题讨论】:
-
固定缓冲区字段作为指针处理,因此调试器将它们显示为
char*字段:它仅显示第一个字符。但是非空指针是可索引的,因此您可以访问所有字符,例如。theStruct.HMACSignature[1]等 -
亲爱的@GyörgyKőszeg,据我所知,调试器将 char* 指针显示为 \0 终止的字符串。当我运行 OP 的代码并中断并在内存窗口中查看结构时,我看到只有每个 char* 变量的第一个字节被设置,其余的设置为零。这就是调试器只显示一个字符的原因,因为 char[] 或 char* 只包含一个字符。
-
不是 C# 调试器:它将指针始终显示为可扩展的树节点。展开后,它会显示基础类型的
ToString值。对于char*,它是单个字符。如果它们显示为以零结尾的字符串,则屏幕截图中的最后一项将是一个空字符串,而不是单个\0字符(另请参阅最后一列:它显示char,而不是字符串)。跨度>
标签: c# byte buffer reinterpret-cast