我正在开发一个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 : 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
}
}
}
你也可以在这里使用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!");
或者如果你有sizeof(T)
约束,你可以使用T : unmanaged
。你不与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
}
}