How to convert unsigned integer arrays to signed arrays and vice versa

Here's a simple technique for converting between signed and unsigned integer arrays.


Introduction

Here's a simple technique for converting between signed and unsigned integer arrays.

The problem

Suppose you have this unsigned array and you'd like to convert it to a signed array.

uint[] uia = { 1, 2, 3, 4 };

Let's try a simple cast first:

int[] ia = (int[])uia;  // doesn't compile!

This doesn't work because the C# compiler is very fussy. It knows that casting uints to ints might cause a problem if the uints are larger than 2,147,483,647 (the maximum allowed for an int) and so disallows it.

So, you'd probably end up doing something like this:

int[] ia = new int[uia.Length];
for (int i = 0; i < ia.Length; i++) ia[i] = (int)uia[i];


Which works but is a bit long winded. So is there an easier way to do?

An easy solution

The answer is 'yes' - just cast it to object before you cast to the new array type!

int[] ia = (int[])(object)uia; // works fine at both compile time and runtime

Why does this work - does it involve boxing?

It works because, by casting to object first, we're postponing the conversion decision until run time.

The CLR is not as fussy as the C# compiler and allows the conversion. If any uint is bigger than Int32.MaxValue (not the case here) it's simply 'wrapped around' to the corresponding negative int value.

As arrays are reference types anyway, there's no boxing here.

Where else does this technique work?

It also works when converting int[] to uint[] and when converting (in either direction) between the other integral types:

byte[] and sbyte[]
ushort[] and short[]
ulong[] and long[]

Of course, you need to be careful when array elements are outside the range of the conversion type (particularly with bytes) unless you're happy for the values to be wrapped around.