I'm curious to know why the C# compiler only gives me an error message for the second if statement.
enum Permissions : ulong { ViewListItems = 1L, } public void Method() { int mask = 138612833; int compare = 32; if (mask > 0 & (ulong)Permissions.ViewListItems > 32) { //Works } if (mask > 0 & (ulong)Permissions.ViewListItems > compare) { //Operator '>' cannot be applied to operands of type 'ulong' and 'int' } }
I've been experimenting with this, using ILSpy to examine the output, and this is what I've discovered.
Obviously in your second case this is an error - you can't compare a ulong
and an int
because there isn't a type you can coerce both to. A ulong
might be too big for a long
, and an int
might be negative.
In your first case, however, the compiler is being clever. It realises that const 1
> const 32
is never true, and doesn't include your if
statement in the compiled output at all. (It should give a warning for unreachable code.) It's the same if you define and use a const int
rather than a literal, or even if you cast the literal explicitly (i.e. (int)32
).
But then isn't the compiler successfully comparing a ulong
with an int
, which we just said was impossible?
Apparently not. So what is going on?
Try instead to do something along the following lines. (Taking input and writing output so the compiler doesn't compile anything away.)
const int thirtytwo = 32; static void Main(string[] args) { ulong x = ulong.Parse(Console.ReadLine()); bool gt = x > thirtytwo; Console.WriteLine(gt); }
This will compile, even though the ulong
is a variable, and even though the result isn't known at compile time. Take a look at the output in ILSpy:
private static void Main(string[] args) { ulong x = ulong.Parse(Console.ReadLine()); bool gt = x > 32uL; /* Oh look, a ulong. */ Console.WriteLine(gt); }
So, the compiler is in fact treating your const int
as a ulong
. If you make thirtytwo = -1
, the code fails to compile, even though we then know that gt
will always be true. The compiler itself can't compare a ulong
to an int
.
Also note that if you make x
a long
instead of a ulong
, the compiler generates 32L
rather than 32
as an integer, even though it doesn't have to. (You can compare an int
and a long
at runtime.)
This points to the compiler not treating 32
as a ulong
in the first case because it has to, merely because it can match the type of x
. It's saving the runtime from having to coerce the constant, and this is just a bonus when the coercion should by rights not be possible.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With