将字节数组复制到通用类型而无需装箱

时间:2019-02-05 15:14:47

标签: c# generics marshalling unsafe

我正在开发一个C#类,其中我需要能够接收一个字节数组并将其复制到相同大小的通用变量中。在C / C ++中,这样的事情(复制)会很容易,但是在C#中不是那么容易。

MyClass<T>
{
  public T Value = default(T);

  public MyClass(byte[] bytes)
  {
    // how to copy `bytes` into `Value`?
  }
}

我不希望使用拳击。有没有办法使用封送处理,反射或不受管/不安全的代码来做到这一点?


我确实找到了this other post,但是唯一建议的答案因为使用拳击而无法正常工作。

1 个答案:

答案 0 :(得分:6)

如果您使用的是最新的.NET,则可以为此使用N(System.Buffers):

Span<T>

您也可以在最新的C#版本中使用class MyClass<T> where T : struct { public T Value = default(T); public MyClass(byte[] bytes) { Value = MemoryMarshal.Cast<byte, T>(bytes)[0]; } } (针对unsafe约束):

T : unmanaged

您还可以使用class MyClass<T> where T : unmanaged { public T Value = default(T); public unsafe MyClass(byte[] bytes) { fixed (byte* ptr = bytes) { Value = *(T*)ptr; // note: no out-of-range check here; dangerous } } } 方法(System.Runtime.CompilerServices.Unsafe)在这里 做一些事情。例如(注意没有约束):

Unsafe.*

如果要检查超出范围的问题:

class MyClass<T>
{
    public T Value = default(T);

    public unsafe MyClass(byte[] bytes)
    {
        T local = default(T);
        fixed (byte* ptr = bytes)
        {
            Unsafe.Copy(ref local, ptr); // note: no out-of-range check here; dangerous
        }
        Value = local;
    }
}

,或者如果您有if (bytes.Length < Unsafe.SizeOf<T>()) throw new InvalidOperationException("Not enough data, fool!"); 约束,则可以使用sizeof(T)。您不需要使用T : unmanaged解决方案(第一个解决方案),因为在这种情况下,原始的Span<T>将产生长度为零的跨度,并且Cast<byte, T>将适当地抛出。


认为这也应该起作用!

[0]

完整示例(可在net462上运行):

public unsafe MyClass(byte[] bytes)
{
    Value = Unsafe.As<byte, T>(ref bytes[0]); // note: no out-of-range check here; dangerous
}