public class Tester
public static void Main()
const uint x=1u;
const int y=-1;
// Let's refactor and inline y... oops!
public long Foo(uint x)
const int y = -1;
var ptr = anIntPtr.ToInt64() + (x + y) * 4096;
const int y=-1
This behaviour is described by section 6.1.9 of the C# standard, Implicit constant expression conversions:
• A constant-expression (§7.19) 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.
So you have
const uint x = 1u; and the constant expression
(x - 1).
According to the specification, the result of that
x - 1 would normally be
int, but because the value of the constant expression (i.e.
0) is within range of
uint it will be treated as
Note that here the compiler is treating the
1 as unsigned.
If you change the expression to
(x + -1) it treats the
-1 as signed and changes the result to
int. (In this case, the
-1 is a "unary operator" which converts the type of the result of
int, so the compiler can no longer convert it to
uint like it could for plain
This part of the specification implies that if we were to change the constant expression to
x - 2 then the result would no longer be a
uint but would instead be converted to
int. However, if you make that change you get a compile error stating that the result would overflow a
That's because of another part of the C# spec, in section 7.19 Constant Expressions which states:
The compile-time evaluation of constant expressions uses the same rules as run-time evaluation of non-constant expressions, except that where run-time evaluation would have thrown an exception, compile-time evaluation causes a compile-time error to occur.
In this case, there would have been an overflow if doing a
checked calculation, so the compiler balks.
With regard to this:
const uint x = 1u; const int y = -1; Console.WriteLine((x + y).GetType()); // Long
That's the same as this:
Console.WriteLine((1u + -1).GetType()); // Long
This is because the -1 is of type
int and the
1u is of type
Section 126.96.36.199 Binary numeric promotions describes this:
• Otherwise, if either operand is of type uint and the other operand is of type sbyte, short, or int, both operands are converted to type long.
(I omitted the part not relevant to this specific expression.)
Addendum: I just wanted to point out a subtle difference in the unary minus (aka "negation") operator between constant and non-constant values.
According to the standard:
If the operand of the negation operator is of type uint, it is converted to type long, and the type of the result is long.
That is true for variables:
var p = -1; Console.WriteLine(p.GetType()); // int var q = -1u; Console.WriteLine(q.GetType()); // long var r = 1u; Console.WriteLine(r.GetType()); // uint
Although for compile-time constants the value of
1 is converted to
uint if an expression involving
uint is using it, in order to keep the whole expression as a
-1 is actually treated as an
I do agree with the OP - this is very subtle stuff, leading to various surprises.