ulong Test2 = UInt32.MaxValue * UInt32.MaxValue
Could be translated to :
UInt32 __temp = UInt32.MaxValue * UInt32.MaxValue; // Overflow
ulong Test2 = (ulong)__temp;
as thee operation on the left of the = sign is always done without any inference on the type on the right obviously not what you want...
It should have been
ulong Test2 = (long)UInt32.MaxValue * UInt32.MaxValue;
That will be treated as :
ulong Test2 = (long)UInt32.MaxValue * (long)UInt32.MaxValue;
And will work.
The rules are in section 16.4.2 of the C# norm :
Numeric promotion consists of
automatically performing certain
implicit conversions of the operands
of the predefined unary and binary
numeric operators. Numeric promotion
is not a distinct mechanism, but
rather an effect of applying overload
resolution to the predefined
operators. Numeric promotion
specifically does not affect
evaluation of user-defined operators,
although user-defined operators can be
implemented to exhibit similar
effects.
As an example of numeric promotion,
consider the predefined
implementations of the binary *
operator:
int operator *(int x, int y);
uint operator *(uint x, uint y);
long operator *(long x, long y);
ulong operator *(ulong x, ulong y);
void operator *(long x, ulong y);
void operator *(ulong x, long y);
float operator *(float x, float y);
double operator *(double x, double y);
decimal operator *(decimal x, decimal y);
When overload resolution rules
(§14.4.2) are applied to this set of
operators, the effect is to select the
first of the operators for which
implicit conversions exist from the
operand types. [Example: For the
operation b * s, where b is a byte
and s is a short, overload resolution
selects operator *(int, int) as the
best operator. Thus, the effect is
that b and s are converted to int, and
the type of the result is int.
Likewise, for the operation i * d,
where i is an int and d is a double,
overload resolution selects operator
*(double, double) as the best operator. end example]