Casting and Conversion
Put simply, a conversion allows an expression to be treated as being a specific type and is typically used to treat an expression of one type as being of a different type. Conversion can be either implicit or explicit, which determines if an explicit cast is required.
All of the predefined types support implicit conversions, shown in Table 3.13, that always succeed. These implicit conversions are allowed because when converting from the original numeric type to the new numeric type, no magnitude can be lost. An explicit conversion is required when there is the possibility of precision being lost as the result of the conversion operation and it requires you to specify the type to which you are converting the original value.
Table 3.13. Implicit Conversions on the Predefined Types
From |
To |
||||||||
short |
ushort |
int |
uint |
long |
ulong |
float |
double |
decimal |
|
sbyte |
|||||||||
byte |
|||||||||
short |
|||||||||
ushort |
|||||||||
int |
|||||||||
uint |
|||||||||
long |
|||||||||
ulong |
|||||||||
char |
|||||||||
float |
For example, an int value can be implicitly converted to a long while the opposite, converting a long to an int, is explicit and requires an explicit cast. The form of an explicit cast is (T)e, where T is the destination (or result) type and e is the expression or variable being cast.
int i = 36; long j = i; // Implicit conversion from int to long. int j = (int)j; // Explicit conversion from long to int.
Boxing and Unboxing Conversions
What happens when you need a value type to act like a reference type? Earlier you learned that, as part of the unified type system, all value types are convertible to object. When a value type variable needs to be used as a reference type, an object “box” is automatically created and the value is copied into the box. When an object box is changed back to its original value type, the value is copied out of the box and into the variable. Once boxed, operations on the boxed variable do not affect the unboxed (original) variable and vice versa.
The following code shows an example of an implicit conversion where the integer variable i is implicitly boxed to an object variable named boxed. That object variable is then explicitly converted back into an integer variable named j.
int i = 36; object boxed = i; // Implicit boxing conversion from int to object. int j = (int)boxed; // Explicit unboxing conversion from object to int.
One of the problems with explicit conversion is that, if you are not careful, you can end up with code that compiles but fails at runtime. An explicit conversion effectively tells the compiler that you are certain the conversion will succeed, and if it doesn’t, a runtime error is acceptable.
To reduce the possibilities of an explicit conversion failing at runtime, C# provides the as operator, which looks like e as T, where e is an expression and T must be either a reference or nullable type. The as operator tells the compiler that there is sufficient reason to believe the conversion will succeed and attempt to convert the value to the specified type. If the conversion was successful, the converted value as T is returned; otherwise a null is returned.
To take advantage of the as operator, the previous code can be rewritten like this:
int? i = 36; object boxed = i; int? j = boxed as int?;