sbyte[] can be magically cast to byte[]

I'm not sure whether this is a .NET bug but I find it really interesting.

As expected, I cannot do this:

sbyte[] sbytes = { 1, 2, 3 };
byte[] bytes = sbytes; // fails: cannot convert source type 'sbyte[]' to taget type 'byte[]'

However, if the type of sbytes is object, this works:

object obj = new sbyte[]{ 1, 2, 3 };
byte[] bytes = obj as byte[];
Assert.IsNull(bytes, "WTF??")

Remark 1: The same issue occurs for int[] - uint[] and the other primitive types as well.

Remark 2: Though the code handles the array as a byte[], the debugger loses the focus and shows ?-s in the array.

screenshot

Remark 3: This works only for arrays, not for the underlying types themselves:

object sbyteObj = (sbyte)1;
byte byteObj = (byte)sbyteObj; // System.InvalidCastException: Specified cast is not valid.

Ok, of course I can check the type like this:

if (obj.GetType() == typeof(byte[]))

Is this an intended behavior of the as operator and direct casting, or is this a .NET bug?

Jon Skeet
people
quotationmark

No, it's not a bug. It's just an impedance mismatch between the C# language rules (which claim there's no conversion available) and the CLR rules (where the conversion is available).

Note that the compiler really, really thinks it knows best:

byte[] bytes = new byte[10];
// error CS0030: Cannot convert type 'byte[]' to 'sbyte[]'
sbyte[] sbytes = (sbyte[]) bytes; 

And even when you've got code that compiles with a warning, it doesn't really do what it says:

byte[] bytes = new byte[10];
// warning CS0184: The given expression is never of the provided ('sbyte[]')
if (bytes is sbyte[])
{
    Console.WriteLine("Yes");
}

Run that code and you don't get output... but if you just change the compile-time type of bytes, it does print Yes:

object bytes = new byte[10];
// No warning now
if (bytes is sbyte[])
{
    Console.WriteLine("Yes"); // This is reached
}

people

See more on this question at Stackoverflow