How to Implement Explicit Type Casting in C

Explicit type casting in C# is a mechanism used to convert a variable from one data type to another when an automatic or implicit conversion is not possible, typically due to the risk of data loss or precision reduction. This article explains how to implement explicit casting using the standard cast operator, how to define custom explicit conversion operators in your own classes and structs, and how to safely handle runtime errors that may occur during the casting process.

The Standard Cast Operator

To explicitly cast a built-in value or reference type, place the target data type inside parentheses directly in front of the value or variable you want to convert. This is commonly required when converting larger numeric types to smaller ones, or when downcasting base class references to derived class references.

double floatingValue = 123.75;

// Explicitly cast double to int (truncates the decimal portion)
int integerResult = (int)floatingValue; 

Console.WriteLine(integerResult); // Outputs: 123

In the example above, casting a double to an int discards the fractional part, resulting in 123.

Implementing Custom Explicit Conversion Operators

For custom types (classes or structs), you can define custom explicit conversions using the explicit and operator keywords. The method must be marked as public static.

public struct Fahrenheit
{
    public double Degrees { get; }

    public Fahrenheit(double degrees)
    {
        Degrees = degrees;
    }

    // Define explicit conversion from Fahrenheit to Celsius
    public static explicit operator Celsius(Fahrenheit f)
    {
        double cDegrees = (f.Degrees - 32) * 5 / 9;
        return new Celsius(cDegrees);
    }
}

public struct Celsius
{
    public double Degrees { get; }

    public Celsius(double degrees)
    {
        Degrees = degrees;
    }
}

To invoke this conversion, use the explicit cast syntax:

Fahrenheit currentTemp = new Fahrenheit(100);

// Explicit conversion from Fahrenheit to Celsius
Celsius convertedTemp = (Celsius)currentTemp; 

Console.WriteLine(convertedTemp.Degrees); // Outputs: 37.77777777777778

Managing Overflow and Runtime Exceptions

Explicit casting can introduce runtime issues such as data truncation or invalid cast failures:

  1. Arithmetic Overflow: By default, integral overflow occurs silently. Use the checked block to force the runtime to throw an OverflowException if values exceed target boundaries:

    int largeNumber = 300;
    
    checked
    {
        // Throws OverflowException because byte can only hold 0-255
        byte smallByte = (byte)largeNumber; 
    }
  2. Reference Type Casting: When casting reference types down an inheritance hierarchy, an invalid cast throws an InvalidCastException. To prevent this, verify compatibility using the is keyword before casting, or use the as operator, which returns null if the cast fails:

    object message = "Hello, World!";
    
    if (message is string text)
    {
        Console.WriteLine(text);
    }