Type Casting
Learn to safely convert values between different data types using implicit and explicit casting techniques.
In this lesson, we’ll explore the concept called type casting, where we convert an object of one type to an object of another type.
Consider the following example:
Line 1: Initializes a
bytevariable namedagewith a value of24.Line 2: Adds
10toage. Since arithmetic operations onbytevalues result in anint, the result is stored in anintvariable namedin10Years.Line 4: Prints the result,
34, to the console.
It’s safe to assume that the value of in10Years is 34. But, if we change the type of in10Years to byte, our code fails to compile:
Line 2: The compiler generates an error here. Even though
34fits in abyte, the addition operation returns anint. We cannot implicitly assign anintto abytebecause of potential data loss.
It fails because C# automatically promotes operands of types like byte and short to int before performing arithmetic operations. Because in10Years is now a byte, we can’t store an integer there automatically. To solve this problem, we cast the result of the arithmetic expression to the desired data type:
Line 4: We perform the addition
age + 10. We then place(byte)before the result to explicitly convert theintback into abytebefore assignment.
Type casting is performed by putting the target data type inside parentheses and placing the whole thing before an expression or variable that we want to cast.
Shrink
In the example above, we shrink an int value into a byte. In C# terminology, this is technically called a narrowing conversion. Although we won’t have any issues in the given code, shrinking can result in unexpected behavior. This is because we’re placing a value into an area of smaller size than the space the value occupies in memory:
byte age = 24;byte someNumber = (byte)(age + 250);
The someNumber variable is a byte, and bytes can hold a whole number up to 255. Because 24 + 250 is 274, it’s too large for a byte to hold. Our typecast forces this value into the smaller container, producing an unexpected result:
Line 10: We add
250to24, resulting in274. We explicitly cast thisintto abyte.Line 12: The output is
18, not274.
Our operation leads to an overflow because 274 is too large for a byte to handle. The byte type wraps around after 255, and this modular arithmetic leads to data loss in the default compiler context.
Shrinking and careless arithmetic operations can lead to these overflows.
The following illustration helps visualize what this narrowing conversion looks like:
Note: C# does not have a native 4-bit integer type. This illustration conceptually shows how narrowing conversions discard higher-order bits when converting to a smaller data type (for example, from
inttobyte).
Expand
Casting to a data type that’s larger in size, technically called a widening conversion, is always safe:
Consider the following example:
Line 2: The
bytevalue is explicitly cast to anint. Sinceintis larger, no data is lost.
This operation is safe because int has enough space to contain all possible values of the byte type. The compiler performs these as implicit conversions, so they do not require specific syntax from the developer.
Line 2: We assign
agedirectly toageAsIntwithout parentheses. The compiler handles this automatically because it is a safe widening conversion.
The compiler informs us if implicit conversion is impossible. In this case, we need to use explicit conversion by putting the target data type inside parentheses like (int)someVariable.
Understand that explicit type casting is possible for compatible data types. We can’t cast a string object to int using this method, for instance.