Reputation: 1010
In C#, the ability to cast between signed and unsigned integer types appears to be influenced by:
object
.Consider the following code example:
// If the variable is declared as a byte array then type casting to sbyte[] results in a
// compile-time error.
byte[] byteArray = new byte[2];
var c = (sbyte[])byteArray; // Compilation eror
// But if the variable is declared as an object then we neither get a compile-time nor a
// run-time error
object byteArrayObject = new byte[2];
var a = (sbyte[])byteArrayObject;
// With an explicitly typed scalar, the byte -> sbyte type conversion succeeds with no errors
byte scalarByte = 255;
var b = (sbyte)scalarByte;
// But if the scalar is declared as an object, an InvalidCastException is thrown at run-time
object byteObject = (byte)4;
var e = (sbyte)byteObject; // InvalidCastException
To summarize:
While this example only considers bytes, the same pattern appears to hold true for other integer types. Can anyone explain why these results are so inconsistent?
Upvotes: 4
Views: 186
Reputation: 32770
The second case has nothing to do with signed or unsigned types. You simply can not unbox a value type to something that is not its exact type. This will also fail:
object i = 1;
var l = (long)i; //Runtime expection: unboxing an int to a long
The first case is an unfortunate mismatch between allowed conversiones in C# and the CLR; C# disallows value type array variance (again, it's more general than signed and unsigned types). When casting from object
the compiler can't disallow it because it simply doesn't have enough information to do so, and the CLR then succeeds.
Do note though, that this only happens with value type arrays. Reference type arrays are variant in C# (unfortunately):
var strs = new string[];
var objs = (object[])strs; //Compiles just fine.
This is unfortunate because it's a broken variance; nobody stops you from doing this:
objs[0] = new object(); //Runtime exception, an object is not a string. Ouch!
Also of interest is that c# generic type variance in interfaces and delegates doesn't work with value types either. A good explanation of why this is so can be found here: here
Upvotes: 2