C-Sharp | Java | Python | Swift | GO | WPF | Ruby | Scala | F# | JavaScript | SQL | PHP | Angular | HTML
And: We see that each new type is converted from the first int and they are strongly typed. These are explicit casts.
Int, uintC# program that performs explicit casting
using System;
class Program
{
static void Main()
{
// 32-bit integer.
int num1 = 1000;
// Cast to long.
long num2 = (long)num1;
// Cast to double.
double num3 = (double)num1;
// Cast to float.
float num4 = (float)num1;
// Cast to uint.
uint num5 = (uint)num1;
// Cast to short.
short num6 = (short)num1;
// Cast to ushort.
ushort num7 = (ushort)num1;
// Cast to decimal.
decimal num8 = (decimal)num1;
// Cast to ulong.
ulong num9 = (ulong)num8;
}
}
Tip: Numeric comparisons, such as comparing an int to a long, also cause implicit casts.
Note: In these cases, lots of computations are taking place in our code that we do not see.
Info: In this example, two conv instructions are generated. There are 12 lines of instructions.
Instructions: The first conv instruction is used to load long value. The second conv instruction is used to compare long to int.
Here: The long's value is loaded with a conv instruction. Then an implicit conversion is done when the two variables are compared.
Note: Numeric types (long, int) always are converted before compared. Sometimes with uint and int no conv instructions are emitted.
C# program that converts long and int
using System;
class Program
{
static void Main()
{
long l = 1000L;
int i = 1000;
if (l == i)
{
Console.WriteLine("True");
}
}
}
Intermediate language after compilation:
.method private hidebysig
static void Main() cil managed
{
.entrypoint
.maxstack 2
.locals init (
[0] int64 l,
[1] int32 i)
L_0000: ldc.i4 0x3e8
L_0005: conv.i8
L_0006: stloc.0
L_0007: ldc.i4 0x3e8
L_000c: stloc.1
L_000d: ldloc.0
L_000e: ldloc.1
L_000f: conv.i8
L_0010: bne.un.s L_001c
L_0012: ldstr "True"
L_0017: call void [mscorlib]
System.Console::WriteLine(string)
L_001c: ret
}
Here: In the example, we removed some casting between long and int and eliminated two conv instructions from being emitted in the IL.
Important: The meaning of the program also changed. It restricts the possible values of the long type.
C# program that avoids casts
using System;
class Program
{
static void Main()
{
int l = 1000;
int i = 1000;
if (l == i)
{
Console.WriteLine("True");
}
}
}
Intermediate language after compile:
.method private hidebysig
static void Main() cil managed
{
.entrypoint
.maxstack 2
.locals init (
[0] int32 l,
[1] int32 i)
L_0000: ldc.i4 0x3e8
L_0005: stloc.0
L_0006: ldc.i4 0x3e8
L_000b: stloc.1
L_000c: ldloc.0
L_000d: ldloc.1
L_000e: bne.un.s L_001a
L_0010: ldstr "True"
L_0015: call void [mscorlib]
System.Console::WriteLine(string)
L_001a: ret
}
Tip: Most of the time, implicit casts are not worth worrying about—but they are always worth understanding.
Also: Sometimes methods specify one integer type, but callers have another integer type. Often it is possible to simply change one method.
Otherwise: The compiler will use static analysis to try to infer the type of the number, or simply raise a warning.
Char: In the C# language, char is defined as a Unicode character, not specifically a numeric value type. It follows different rules.
And: You cannot compare a char to an int directly. You can cast the char to an int explicitly.
CharInfo: Checked provides a way to more easily detect when a number type is not large enough to store the required value.
CheckedMaxValue, MinValue: Each numeric type has a maximum and minimum value. Larger types have larger maximums.
int.MaxValue