Warning ahead: this article explains a dirty trick that should only be used in very specific circumstances (when memory conditions are low). I’ve personally seen this used when loading a large image from file (as a byte array) and needing to pass this array to a piece of legacy code that only accepts an array of shorts. Due to the size of the image, it was not feasible to copy the data.
Casting arrays of value types can be problematic. Image that you need to cast a large array of unsigned integers to an array of signed integers.
Our first experiment might be like this:
This does not work. We get an ArrayTypeMismatchException because the two types are not compatible (the rules for compatible types are explained here).
The solution is to use the Marshal.Copy() method. This requires unsafe code however.
Here is an example:
This seems to work, but instead of casting the array we really made a copy of the array. The differences are subtle but can be important:
- the copy requires its own memory. If the array is very large, this can be a problem. I’ve encountered situations (e.g. in image processing) where this was not acceptable.
- when the copy is modified, the original array is left untouched. This is not what should happen when we cast a variable.
Using a dirty trick it is possible to cast an array of value types without copying the data. Look at this sample code:
We’re using a Converter-struct that uses some interop-magic to define two fields that map to the same location in memory. Now we can access the same data as an int or as an uint. The data is not copied in any way!
Note that this is a dirty trick: we fool the compiler into thinking that the type of the array is changed but it really is not. You can verify this by calling GetType() on the returned array: it will return System.UInt32.
This trick can be used in other situations as well, for instance to access an array of integers as an array of bytes (without copying the data).
Warning: if the size of the array to be converted is reasonably small, you should just copy the data! Only use this trick if you really cannot afford to copy the data! This trick violates the type-safety of the runtime and is not guarantee to work in all situations or in future versions of .NET!