如果数据来自C/C++ struct ,那么从字节[]数组填充C# struct 的最佳方法是什么?C struct 看起来像这样(我的C非常Rust ):

typedef OldStuff {
    CHAR Name[8];
    UInt32 User;
    CHAR Location[8];
    UInt32 TimeStamp;
    UInt32 Sequence;
    CHAR Tracking[16];
    CHAR Filler[12];
}

这样的话:

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

如果OldStuff作为字节[]数组传递,那么将OldStuff复制到NewStuff的最佳方式是什么?

我目前正在做类似以下的事情,但感觉有点笨拙.

GCHandle handle;
NewStuff MyStuff;

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();

有没有更好的方法来实现这一点?


与固定内存和使用Marshal.PtrStructure相比,使用BinaryReader类是否会带来任何性能提升?

推荐答案

根据我在该上下文中看到的情况,您不需要将SomeByteArray复制到缓冲区中.您只需从SomeByteArray中获取句柄,将其固定,使用PtrToStructure复制IntPtr数据,然后释放即可.不需要复印件.

这将是:

NewStuff ByteArrayToNewStuff(byte[] bytes)
{
    GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
    try
    {
        NewStuff stuff = (NewStuff)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(NewStuff));
    }
    finally
    {
        handle.Free();
    }
    return stuff;
}

通用版本:

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;
}

更简单的版本(需要unsafe个交换机):

unsafe T ByteArrayToStructure<T>(byte[] bytes) where T : struct
{
    fixed (byte* ptr = &bytes[0])
    {
        return (T)Marshal.PtrToStructure((IntPtr)ptr, typeof(T));
    }
}

.net相关问答推荐

为什么Regex.Escape支持数字符号和空格?

为什么我在环境变量中有不同的值?

C#.Net 中的可选返回

类似于字典但没有值的 C# 数据 struct

为什么 Any() 不适用于 c# null 对象

为什么 SortedSet.GetViewBetween 不是 O(log N)?

C#6.0 字符串插值本地化

为什么我得到 411 Length required 错误?

使用 C# 清除文本文件的内容

为什么 ?: 会导致转换错误,而 if-else 不会?

如何在 C# 中直接执行 SQL 查询?

从 Web.Config 中的邮箱友好显示名称存储 Smtp

覆盖方法上的 C# 可选参数

如何比较 C# 中的(目录)路径?

为什么使用 ImmutableList 而不是 ReadOnlyCollection?

如何异步 Files.ReadAllLines 并等待结果?

SQLParameter 如何防止 SQL 注入?

强制 XmlSerializer 将 DateTime 序列化为 'YYYY-MM-DD hh:mm:ss'

枚举和匹配属性的 C# 命名约定

无法添加对 dll 的引用