Type conversion (also known as casting or coercion) is the process of transforming a value from one data type to another.
This may be necessary when working with different data types and a specific value needs to be treated as another type.
There are two main types of conversions in C#, implicit conversions and explicit conversions.
Implicit Conversions
Implicit conversions are those that the compiler performs automatically (without us having to do anything).
This occurs only when there is no risk of data loss, usually when the destination data type is larger than the source data type.
For example,
int integerNumber = 10;
long longNumber = integerNumber;
In this case, the variable integerNumber
is implicitly converted to long
and assigned to the variable longNumber
.
This is the case because we have a variable of type int
and we want to assign its value to a variable of type long
, which is larger than int
. Therefore, there is no risk, and C# will automatically perform the implicit conversion:
Explicit Conversions
Explicit conversion (also known as casting) is used when a data conversion cannot be performed automatically by the compiler. For example, because there is possible data loss, or because the compiler does not “dare” to do it on its own.
To perform an explicit conversion in C#, it is necessary to use the casting operator
(dataType)object
Where,
- dataType: is the destination data type
- object: is the object that you want to convert.
For example, if we have a variable of type double
and we want to convert it to an int
type, we need to perform an explicit conversion:
double decimalNumber = 3.14;
int integerNumber = (int)decimalNumber;
In this case, we use the casting (int)
to convert the variable decimalNumber
to int
. It is important to note that, in this example, the decimal part of the original number will be lost.
Conversion between reference types
It is also possible to perform conversions between reference types (such as classes and interfaces). These conversions can be more complex and require knowledge of the type hierarchy we are working with.
Casting between different reference types should be done carefully, and only if we are sure that the conversion is valid.
If the conversion is not valid, it will cause a runtime error 💥
Conversion from base classes to derived classes
public class Animal
{
public void MakeSound()
{
Console.WriteLine("Animal sound");
}
}
public class Dog : Animal
{
public void Bark()
{
Console.WriteLine("Woof!");
}
}
public class Program
{
public static void Main()
{
Animal myAnimal = new Dog(); // Implicit conversion from Dog to Animal
Dog myDog = (Dog)myAnimal; // Explicit conversion from Animal to Dog
myDog.Bark(); // Output: Woof!
}
}
In this example, myAnimal
is implicitly converted to Animal
when instantiated as Dog
. Then, an explicit conversion from Animal
to Dog
is performed to access the specific method of the derived class Dog
.
Using is
and as
operators
The is
and as
operators facilitate safe checking and conversion between reference types.
is
Operator
The is
operator is used to check if an object is of a specific type.
object obj = "Hello, World!";
if (obj is string)
{
Console.WriteLine("obj is a string");
}
as
Operator
The as
operator attempts to convert an object to a specified type and returns null
if the conversion fails.
object obj = "Hello, World!";
string str = obj as string;
if (str != null)
{
Console.WriteLine("The conversion was successful: " + str);
}
else
{
Console.WriteLine("The conversion failed");
}
User-defined conversion
C# allows the definition of custom conversions between types by overloading the implicit
and explicit
conversion operators.
User-defined implicit conversion
public class Celsius
{
public float Degrees { get; set; }
public Celsius(float degrees)
{
Degrees = degrees;
}
public static implicit operator Fahrenheit(Celsius c)
{
return new Fahrenheit((c.Degrees * 9 / 5) + 32);
}
}
public class Fahrenheit
{
public float Degrees { get; set; }
public Fahrenheit(float degrees)
{
Degrees = degrees;
}
}
public class Program
{
public static void Main()
{
Celsius celsius = new Celsius(25);
Fahrenheit fahrenheit = celsius; // Implicit conversion
Console.WriteLine(fahrenheit.Degrees); // Output: 77
}
}
User-defined explicit conversion
public class Celsius
{
public float Degrees { get; set; }
public Celsius(float degrees)
{
Degrees = degrees;
}
public static explicit operator Fahrenheit(Celsius c)
{
return new Fahrenheit((c.Degrees * 9 / 5) + 32);
}
}
public class Fahrenheit
{
public float Degrees { get; set; }
public Fahrenheit(float degrees)
{
Degrees = degrees;
}
}
public class Program
{
public static void Main()
{
Celsius celsius = new Celsius(25);
Fahrenheit fahrenheit = (Fahrenheit)celsius; // Explicit conversion
Console.WriteLine(fahrenheit.Degrees); // Output: 77
}
}
Practical examples
Let’s look at some examples of conversions between basic types.
Conversion from int
to float
int integerNumber = 100;
float floatNumber = integerNumber; // Implicit conversion
Console.WriteLine(floatNumber); // Output: 100
Conversion from double
to int
double doubleNumber = 123.456;
int integerNumber = (int)doubleNumber; // Explicit conversion
Console.WriteLine(integerNumber); // Output: 123 (the decimal part is lost)
Conversion from char
to int
char letter = 'A';
int asciiCode = (int)letter; // Explicit conversion
Console.WriteLine(asciiCode); // Output: 65 (ASCII code of 'A')