加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c# – 将字节数组复制到通用类型而不进行装箱

发布时间:2020-12-16 01:28:30 所属栏目:百科 来源:网络整理
导读:我正在开发一个C#类,其中我需要能够接受一个字节数组并将其复制到相同大小的通用变量.在C/C++这样的事情(复制)会很容易,但在C#中并没有那么多. MyClassT{ public T Value = default(T); public MyClass(byte[] bytes) { // how to copy `bytes` into `Value`
我正在开发一个C#类,其中我需要能够接受一个字节数组并将其复制到相同大小的通用变量.在C/C++这样的事情(复制)会很容易,但在C#中并没有那么多.

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

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

我宁愿不使用拳击.有没有办法使用编组,反射或非托管/不安全代码?

我确实找到了this other post,但唯一建议的答案是行不通的,因为它使用拳击.

解决方法

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

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

    public MyClass(byte[] bytes)
    {
        Value = MemoryMarshal.Cast<byte,T>(bytes)[0];
    }
}

您还可以在最近的C#版本中使用unsafe(对于T:非托管约束):

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

你也可以使用Unsafe.*方法(System.Runtime.CompilerServices.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!");

或者如果你有T:unmanaged约束,你可以使用sizeof(T).您不需要使用Span< T>解决方案(第一个),因为原始的Cast< byte,T>在这种情况下,将产生一个长度为零的跨度,[0]将适当地抛出.

我认为这也应该有效!

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

完整示例(适用于net462):

using System;
using System.Runtime.CompilerServices;


struct Foo
{
    public int x,y;
}
class MyClass<T>
{
    public T Value = default(T);

    public unsafe MyClass(byte[] bytes)
    {
        if (bytes.Length < Unsafe.SizeOf<T>())
            throw new InvalidOperationException("not enough data");
        Value = Unsafe.As<byte,T>(ref bytes[0]);
    }
}
static class P
{
    static void Main() {
        byte[] bytes = new byte[] { 1,2,3,4,5,6,7,8 };
        var obj = new MyClass<Foo>(bytes);
        var val = obj.Value;
        Console.WriteLine(val.x); // 67305985 = 0x04030201
        Console.WriteLine(val.y); // 134678021 = 0x08070605 
    }
}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读