Why Does "Int[] Is Uint[] == True" in C#

Why does int[] is uint[] == true in C#

C# and the CLR have somewhat different conversion rules.

You can't directly cast between int[] and uint[] in C# because the language doesn't believe any conversion is available. However, if you go via object the result is up to the CLI. From the CLI spec section 8.7 (I hope - I'm quoting an email exchange I had on this topic with Eric Lippert a while ago):

Signed and unsigned integral primitive
types can be assigned to each other;
e.g., int8 := uint8 is valid. For this
purpose, bool shall be considered
compatible with uint8 and vice versa,
which makes bool := uint8 valid, and
vice versa. This is also true for
arrays of signed and unsigned integral
primitive types of the same size;
e.g., int32[] := uint32[] is valid.

(I haven't checked, but I assume that this sort of reference type conversion being valid is what makes is return true as well.)

It's somewhat unfortunate that there are disconnects between the language and the underlying execution engine, but it's pretty much unavoidable in the long run, I suspect. There are a few other cases like this, but the good news is that they rarely seem to cause significant harm.

EDIT: As Marc deleted his answer, I've linked to the full mail from Eric, as posted to the C# newsgroup.

Why does Random.Next() return an int instead of uint?

uint is not CLS-Compliant.

Here is some great reading on the topic:

http://msdn.microsoft.com/en-us/library/vstudio/bhc3fa7f(v=vs.100).aspx

Why does this implicit conversion from int to uint work?

Integer constant conversions are treated as very special by the C# language; here's section 6.1.9 of the specification:

A constant expression of type int can be converted to type sbyte, byte, short, ushort, uint, or ulong, provided the value of the constant-expression is within the range of the destination type. A constant expression of type long can be converted to type ulong, provided the value of the constant expression is not negative.

This permits you to do things like:

byte x = 64;

which would otherwise require an ugly explicit conversion:

byte x = (byte)64; // gross

Why does typeof(IList uint ).IsAssignableFrom(typeof(int[]) return true?

It is assignable because it works if you cast explicitly:

IList<UInt16> x = (IList<UInt16>)(IList)new Int16[] { };

So you just can't let it cast implictly to the target type.

why is a cast from IList to List<UInt16> valid but a cast from IList
to IList<UInt32> invalid?

Before i start to explain it in my words, read Jon Skeets answer:

You can't directly cast between int[] and uint[] in C# because the
language doesn't believe any conversion is available. However, if you
go via object(*or IList in my example) the result is up to the CLI.

CLI spec section 8.7

Signed and unsigned integral primitive types can be assigned to each
other; e.g., int8 := uint8 is valid. For this purpose, bool shall be
considered compatible with uint8 and vice versa, which makes bool :=
uint8 valid, and vice versa. This is also true for arrays of signed
and unsigned integral primitive types of the same size; e.g., int32[] := uint32[] is valid.

C# object equals int doesn't equal true

Since Equals is a virtual method it will call the appropriate method of the subclass of object. In this case int.Equals. In a very simple example:

object o = 4;
int i = 4;

o.Equals(i) returns true. So your problem is somewhere else. Maybe objectValue is not an int, but a byte, short or other numerical type.

Why does casting a value as IEnumerable T behave differently based on how I initialized the value?

I think that's because of unusual differences between how C# and CLR treats conversions between int and uint, as described in this answer. First note that this code won't compile:

uint[] a1 = new[] { 1u };
var a2 = (int[])a1;

Because C# doesn't believe there exists a cast. However if you go this way:

uint[] a1 = new[] { 1u };
var a2 = (int[]) (object) a1;

Runtime will decide if this cast is valid or not, and it (CLR) thinks differently and allows casting from uint[] to int[] (and visa versa), as desribed in answer I linked.

But the same is not true for List<int> and List<uint> - they are not treated in a special way by CLR and as such cannot be cast between each other.

So in your case, uint[] can be cast to int[] and int[] implements IEnumerable<int>, so your idList is not null. This is not true for Lists - hence your problem.

As for why ToList fails in first case, that's because internally it does something like that:

 uint[] a1 = new[] { 1u };
var a2 = (int[]) (object) a1;
// ToList copies contents to new array
int[] copy = new int[a2.Length];
Array.Copy(a2, copy, a2.Length);

And Array.Copy checks directly if type of elements in one array are compatible with type of elements in another array.

Boolean int conversion issue

There is no implicit conversion of a bool to an int. Only an explicit one:

Convert.ToInt32(someBool)
// or...
someBool ? 1 : 0

From that site you linked:

First, you cannot implicitly convert from bool to int. The C# compiler uses this rule to enforce program correctness. It is the same rule that mandates you cannot test an integer in an if statement.

Edit

int doesn't have a concept of infinity. Only float and double do. This means it won't be related to that parameter, unless that parameter just controls the flow of the code that is actually crashing. Which still means it isn't the conversion causing the problem.

You're getting a different error for int.Parse("false") because it is expecting a number, not a true/false value. This will always throw an exception at runtime, but it will throw in your code, not in the library's code.

I'm starting to think it is the second parameter, contract, for which you've supplied AUDUSD.



Related Topics



Leave a reply



Submit