Last Updated:

Unsafe cast'ing in .Net

I decided here the other day to do a little programming, and not for work, but so, for myself, more precisely for my phone ;). There was such a task - to load an array of floats from a binary file, and do it as efficiently as possible in terms of performance (for the phone after all).

It turned out that it was not so easy to do this in the dotnet. There are 2 ways - the first is to use BinaryReader and in a loop to read numbers from the file, and the second is to read the entire file into a byte array (byte[]) and then copy from it to float[]. And both of these options clearly did not suit me - the first because it is slow (as far as I did not measure of course, but even function calls will take quite a decent time if a large number of numbers need to be read), and the second - because it will take twice the amount of memory - first for a byte array, then for a float array.

The ideal option would be, of course, to read all the data of the file into a byte array at once and then simply bring it to float[], then we will read it quickly and we will not eat up the excess memory. But you can't do that to the ground!

 

Very upset, I went to look for a solution on the Internet, and found that I was not the only one like this -)))) On many forums, the same question was asked and there was no answer to it, and only when I completely lost hope and began to tear my hair out on my ass to think about rewriting everything on siplipus, I came across the brilliant solution of one omerecos. He suggested that nae.. trick dotnet as follows: use a class that uses explicit StructLayout for its members, in other words:

 

That is, the class contains a byte array and a float array, but they are in the same location. That is, we read the byte array from the file, and then we can simply access it as a float array. Urra, comrades! Now how to use this in code:

 

But there are a few points here that should not be forgotten. Since the arrays use the same memory area,

1) in debug mode, viewing these values is impossible and the Watch for them does not work correctly (the studio is slightly crazy), that is, if you put a breakpoint and hover the mouse over buffer.floats, it will show that this is a byte array -)))). But at run time, the program works correctly.

2) the length of the array is incorrectly determined. If, for example, you make buffer.bytes = new byte[4000], then buffer.floats.Length will also be 4000, although in fact there are only 1000 of them, you need to remember this and do not try to read outside the array. As far as I understand, the length of the array is shown in the elements of the array that was first created.

3) (this is only a guess, I was too lazy to check :) If you initialize both arrays, there may be a memory leak -))))

And of course, these transformations work only for value-types for obvious reasons.

That's it, now you can make any unsafe castes for value-types, lucky you destroy heap! 😉