Expanding on my comment; below you'll find a very simple program that compares the method I suggested with your original example. The results on my machine show that the MemoryMarshal
class is about 85x faster. You might want to experiment a bit and try running a similar test with a larger struct; maybe your method is faster for the specific problem that you're trying to solve.
Comparison Code:
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
using System;
using System.Runtime.InteropServices;
public readonly struct SomeStruct
{
private readonly ulong m_x;
private readonly ulong m_y;
private readonly ulong m_z;
public ulong X => m_x;
public ulong Y => m_y;
public ulong Z => m_z;
public SomeStruct(ulong x, ulong y, ulong z) {
m_x = x;
m_y = y;
m_z = z;
}
}
public class Race
{
private readonly byte[] m_data = new byte[] {
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
1, 255, 0, 0, 0, 0, 0, 0,
};
[Benchmark(Baseline = true)]
public SomeStruct A() => MemoryMarshal.Read<SomeStruct>(m_data);
[Benchmark]
public SomeStruct B() => Program.ReadUsingMarshalUnsafe<SomeStruct>(m_data, 0, m_data.Length);
}
class Program
{
static void Main(string[] args) {
var summary = BenchmarkRunner.Run<Race>();
Console.ReadKey();
}
public static T ReadUsingMarshalUnsafe<T>(byte[] data, int startIndex, int length) {
byte[] fixedData = new byte[length];
unsafe {
fixed (byte* pSource = data, pTarget = fixedData) {
int index = 0;
for (int i = startIndex; i < data.Length; i++) {
pTarget[index] = pSource[i];
index++;
}
}
fixed (byte* p = &fixedData[0]) {
return (T)Marshal.PtrToStructure(new IntPtr(p), typeof(T));
}
}
}
}
**BenchmarkDotNet Results:**