You're already using unsafe code, so why not simply get a pointer to the structure and pass it? Doesn't this work?
MyBuffer bf = new MyBuffer();
bf.L1 = 23;
unsafe
{
MyBuffer* pStruct = &bf;
YourNativeMethod(pStruct);
}
[DllImport]
static extern void YourNativeMethod(MyBuffer* pStruct);
To avoid all marshalling, you might have to write a C++/CLI wrapper, I'm not sure if .NET does marshalling even if you pass an unsafe pointer.
You don't even need the byte-array, the native method certainly doesn't care whether you're passing a pointer to a byte array or a structure. Everything is a byte array :D
EDIT: Since your case doesn't explicitly call a native method, we have to go around this.
The problem is, fixed byte[] isn't actually a byte array at all. It's simply a sequence of 17 bytes, nothing more. That's not enough for a .NET array. So we have to copy it to a new array (it might be worthwhile to keep "buffer" byte arrays ready and recycle them to avoid allocations and deallocations). This can be done either through Marshal.Copy
or some unsafe pointer fun:
byte[] bytes = new byte[17];
unsafe
{
IntPtr srcPtr = new IntPtr(bf.Bytes);
{
Marshal.Copy(srcPtr, bytes, 0, 17);
}
}
This uses direct memory copying, but does some checks. In my testing, it's a great way to copy bigger arrays (for me the break-even point was somewhere around 50 bytes). If your array is smaller, the overhead of those checks gets higher compared to total copy time, so you might want to use byte-by-byte copying instead:
byte[] bytes = new byte[17];
unsafe
{
byte* srcPtr = bf.Bytes;
fixed (byte* bPtr = bytes)
{
var j = 0;
while (j++ < 17)
{
*(bPtr + j) = *(srcPtr++);
}
}
}
I hope I don't have to tell you to be careful around this kind of code :)
In any case, I wouldn't worry about the performance too much and I'd use the Marshal.Copy
variant, simply because your DB call is going to be the bottle-neck anyway. The safer option is better :)
There's also a few tricks you can use to speed this up, for example copying a whole int
or long
at a time, which the CPU is much better, although it's trickier. Trying with a simple variant (a length with a multiple of 4, copying a whole int at a time) cut my test runtime by four. If your data length is not a multiple of four, you'd simply copy the remainder as bytes.