Cette tâche consiste à convertir un tableau d'octets contenant des données d'une structure C/C en la structure C# correspondante. La structure C/C ressemble à ceci :
<code class="language-c++">typedef struct OldStuff { CHAR Name[8]; UInt32 User; CHAR Location[8]; UInt32 TimeStamp; UInt32 Sequence; CHAR Tracking[16]; CHAR Filler[12]; } OldStuff;</code>
La structure C#, nommée NewStuff
, est définie comme suit :
<code class="language-csharp">[StructLayout(LayoutKind.Explicit, Size = 56, Pack = 1)] public struct NewStuff { [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)] [FieldOffset(0)] public string Name; [MarshalAs(UnmanagedType.U4)] [FieldOffset(8)] public uint User; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)] [FieldOffset(12)] public string Location; [MarshalAs(UnmanagedType.U4)] [FieldOffset(20)] public uint TimeStamp; [MarshalAs(UnmanagedType.U4)] [FieldOffset(24)] public uint Sequence; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)] [FieldOffset(28)] public string Tracking; }</code>
Dans un premier temps, une approche plus lourde a été envisagée, impliquant une mémoire épinglée et utilisant Marshal.PtrToStructure
:
<code class="language-csharp">int BufferSize = Marshal.SizeOf(typeof(NewStuff)); byte[] buff = new byte[BufferSize]; Array.Copy(SomeByteArray, 0, buff, 0, BufferSize); handle = GCHandle.Alloc(buff, GCHandleType.Pinned); MyStuff = (NewStuff)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(NewStuff)); handle.Free();</code>
Après une analyse plus approfondie, il a été déterminé que la copie tampon dans la méthode d'origine n'était pas nécessaire. Au lieu de cela, l’épinglage direct de la poignée est suffisant :
<code class="language-csharp">GCHandle handle; NewStuff MyStuff; handle = GCHandle.Alloc(SomeByteArray, GCHandleType.Pinned); try { MyStuff = (NewStuff)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(NewStuff)); } finally { handle.Free(); }</code>
En outre, une version encore plus simple peut être utilisée en utilisant des génériques (nécessite une commutation non sécurisée) :
<code class="language-csharp">T ByteArrayToStructure<T>(byte[] bytes) where T : struct { T stuff; GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned); try { stuff = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T)); } finally { handle.Free(); } return stuff; }</code>
<code class="language-csharp">unsafe T ByteArrayToStructure<T>(byte[] bytes) where T : struct { fixed (byte* ptr = &bytes[0]) { return (T)Marshal.PtrToStructure((IntPtr)ptr, typeof(T)); } }</code>
Bien que la solution préférée implique la fixation et Marshal.PtrToStructure
, dans certains cas, l'analyse des données à l'aide de la classe BinaryReader
peut offrir des avantages en termes de performances. Cependant, des mises en œuvre spécifiques doivent être évaluées pour déterminer si ces gains sont significatifs.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!