C# Implicit vs Explicit Conversion: Differences + Examples

Dec 8, 2021 | .NET, C#

After many years programming in .NET, you may have already realized that the framework allows us, in a very simple way, to make conversions between different types of data.

Conversions can be of 2 types 👇

  • Implicit Conversions
  • Explicit Conversion

Implicit Conversions

Implicit conversions are for which it is not necessary to indicate the conversion in parentheses (…).

double variable = 10;

In the code we assign a variable of type double a value of type int.

But the compiler doesn’t tell us anything and lets us continue working as if nothing had happened. This is known as an implicit conversion.

Instead, if we do the following 👇

int variable = 10.0;

The compiler will give us an error indicating that an implicit conversion from double to int cannot be done, and tells us to use an explicit conversion.

Explicit Conversions

There is no mystery about it, simply this problem can be fixed by putting (int) in front of 10.0 ðŸ‘‡

int variable = (int) 10.0;

Placing the type of data to which we want to convert it in parentheses is called explicit conversion. What this means is that with this syntax we are explicitly indicating to the compiler that we want to convert one type of data into a different one.

At this point you could perfectly tell me that this would also work 👇

double variable = (double) 10;

Apparently it does the same as if we don’t put (double) in front of it.

So… where is the difference? 🤔

The only difference between implicit and explicit conversions has to do with whether or not there is a risk of that information being lost.

If we go to the first case (without parentheses), it is an implicit conversion. The value of the litetal int does not matter as if we write double since there will be no risk of losing the information as it is a type of greater capacity.

On the contrary, if we go to the second case, we are forced to do an explicit conversion. This works because a double object can contain values ​​that a smaller capacity int type cannot represent.

Let’s take an example 👇

int variable = (int) 10.5;

How we can create our own conversions

Usually the conversions of the Framework are more than enough for the needs that arise. However, there may be many cases where it would be more useful to define our own implicit and explicit conversions. The .NET platform provides us with an easy way to do it.

To create a conversion between two types, we simply have to write the corresponding operator, either implicit or explicit.

We are going to create an imaginary scenario in which we have to manage the temperatures so that the degrees can change between Celsius and Fahrenheit.

Let’s create the code 👇

class Temperature
{
    public float Degrees { get; set; }
}

class Celsius : Temperature
{
    public Celsius(float temp)
    {
        Degrees = temp;
    }
}

class Fahrenheit : Temperature
{
    public Fahrenheit(float temp)
    {
        Degrees = temp;
    }
}

Now with this code we have the possibility of writing methods so that we do the conversion between them, and which we call each time.

class Temperature
{
    public float Degrees { get; set; }

    public Celsius ToCelsius()
    {
        return new Celsius(((5.0f / 9.0f) * (this.Degrees - 32)));
    }

    public Fahrenheit ToFahrenheit()
    {
        return new Fahrenheit(((9.0f / 5.0f) * this.Degrees + 32));
    }
}

Celsius cel = new Celsius(10);
Fahrenheit far = cel.ToFahrenheit();
Celsius cel2 = far.ToCelsius();

This works, but we will have to call the corresponding method each time and this makes the code very messy.

If we want to do an implicit conversion, we simply have to define a static operator with the static implicit operator.

We go back to our example 👇

class Temperature
{
    public float Degrees { get; set; }
}

class Celsius : Temperature
{
    public Celsius(float temp)
    {
        Degrees = temp;
    }
    
    public static implicit operator Fahrenheit(Celsius c)
    {
        return new Fahrenheit((9.0f / 5.0f) * c.Degrees + 32);
    }
}

class Fahrenheit : Temperature
{
    public Fahrenheit(float temp)
    {
        Degrees = temp;
    }
    
    public static implicit operator Celsius(Fahrenheit fahr)
    {
        return new Celsius((5.0f / 9.0f) * (fahr.Degrees - 32));
    }
}

Celsius cel = new Celsius(10);
Fahrenheit far = cel;
Celsius cel2 = far;

We can see that to each class we add an implicit conversion operator for the other related class, and after that, we just implicitly perform the conversions.

What we gain from this is a much cleaner code that meets the conditions for implicit conversions.

If we want to do it differenty

  • Let’s imagine that we have an application that has to manage the teachers and students of a school.

Let’s see it better 👇

public class Person
{
    public string Name { get; set; }
}

public class Pupil : Person
{
    public string Class { get; set; }
    public List<int> IdsCourse { get; set; }
}

public class Teacher : Person
{
    public string Class { get; set; }
    public int IdContract { get; set; }
}

If at some point a student becomes a teacher or vice versa, we will need to use a conversion to reuse the data. As in this case, we are going to lose information since the different classes do not handle the same information.

Therefore the conversion will have to be explicit ðŸ‘‡

public class Person
{
    public string Name { get; set; }
}

public class Pupil : Person
{
    public string Class { get; set; }
    public List<int> IdsCourse { get; set; }

    public static explicit operator Teacher(Pupil alum)
    {
        return new Teacher { Name = alum.Name, Class = alum.Class, IdContract = -1 };
    }
}

public class Teacher : Person
{
    public string Class { get; set; }
    public int IdContract { get; set; }

    public static explicit operator Pupil(Teacher prof)
    {
        return new Pupil { Name = prof.Name, Class = prof.Class, IdsCourse = new List<int>() };
    }
}

Teacher teacher = new Teacher { Name = "Juan", Class = "Programming", IdContract = 10 };
Pupil student = (Pupil)teacher;
Teacher teacher2 = (Teacher)student;

Advanced Conversion Techniques

Next, we’re going to dive into some advanced conversion techniques that you can’t miss. And yes, I promise I won’t bore you this time!

Using System.Convert for Conversions

Don’t forget that C# provides the System.Convert class which comes preloaded with a bunch of handy conversion methods. This helps when you need to handle conversions in a safer and more controlled manner. Take a look at this example:

int intNumber = 42;
double doubleNumber = Convert.ToDouble(intNumber);

You can also handle conversion scenarios that might throw exceptions, by using methods like Int32.TryParse(), giving you the opportunity to take alternative action.

string userInput = "42";
int parsedNumber;

if (Int32.TryParse(userInput, out parsedNumber))
{
    Console.WriteLine("Parsed successfully! Number is: " + parsedNumber);
}
else
{
    Console.WriteLine("Oops! Invalid number.");
}

It always pays off to be cautious, doesn’t it?

Dealing with Nullable Types

Nullable types sure can be tricky! But with explicit and implicit conversions combined with the power of C#, you can easily handle nullable types like a pro. Check this out:

int? aNullableInt = 10;
double? convertedDouble = aNullableInt; // Implicit conversion

double? anotherNullableDouble = 20.5;
int? explicitlyConvertedInt = (int?)anotherNullableDouble; // Explicit conversion

Just remember to be extra careful with nulls, as they can lead to runtime exceptions if not handled properly. You’ve been warned! 🙂

Real-Life Examples

Currency Conversion Example

Here’s an example of currency conversion done the C# way, using custom implicit and explicit conversions:

public class Dollar
{
    public decimal Amount { get; }

    public Dollar(decimal amount)
    {
        Amount = amount;
    }

    // Implicit conversion from Dollar to Euro
    public static implicit operator Euro(Dollar dollar)
    {
        decimal conversionRate = 0.85m; // Simulated conversion rate
        return new Euro(dollar.Amount * conversionRate);
    }        
}

public class Euro
{
    public decimal Amount { get; }

    public Euro(decimal amount)
    {
        Amount = amount;
    }

    // Explicit conversion from Euro to Dollar
    public static explicit operator Dollar(Euro euro)
    {
        decimal conversionRate = 1.18m; // Simulated conversion rate
        return new Dollar(euro.Amount * conversionRate);
    }
}

// Usage
Dollar dollars = new Dollar(100m);
Euro euros = dollars; // Implicit conversion
Dollar convertedDollars = (Dollar)euros; // Explicit conversion

It’s like magic, isn’t it?

Handling Complex Data Structures

When working with complex data structures, you may need to apply multiple explicit and implicit conversions in sequence to achieve your desired result. Let’s see a real-life example with a graph:

public class GraphNode<T>
{
    public T Value { get; set; }
    public List<GraphNode<T>> Neighbors { get; set; }

    // Assorted methods...

    // Implicit conversion from T to GraphNode<T>
    public static implicit operator GraphNode<T>(T value)
    {
        return new GraphNode<T> { Value = value, Neighbors = new List<GraphNode<T>>() };
    }

    // Explicit conversion from GraphNode<T> to T
    public static explicit operator T(GraphNode<T> node)
    {
        return node.Value;
    }
}

// Usage
GraphNode<int> node = 10; // Implicit conversion from int to GraphNode<int>
int intValue = (int)node; // Explicit conversion back to int

The Real Deal: Common Pitfalls & Best Practices

  • Remember that implicit conversions should be used only when there’s no risk of data loss, then you can use explicit conversions.
  • Keep the use of user-defined conversions to a minimum, and avoid overloading
  • operators unnecessarily, as it can lead to confusion and decreased readability.
  • Whenever possible, use built-in conversion methods such as System.Convert and TryParse methods for a safer and more controlled way to handle conversions.
  • Be cautious when dealing with nullable types and null reference exceptions. Always validate your input data and handle nullability appropriately.

Going the Extra Mile: Making Your Code Efficient

When working with conversions, always strive to ensure your code is efficient on both memory and performance fronts. Here are some tips to help you achieve that:

  1. Cache and reuse conversion factors and other frequently used data, rather than recomputing them.
  2. If you’re implementing custom conversion operators, make sure that they exhibit consistent behavior across different types.
  3. When dealing with large datasets or high performance environments, consider using specialized libraries for performing conversions. They often provide better optimization and performance than hand-written custom conversions.

Keep Your Code Clean & Organized

Above all, keep your code clean and organized by using appropriate comments and method names. Proper organization and documentation of your code will greatly improve its readability and maintainability in the long run.

Parting Thoughts

Mastering the art of implicit and explicit conversions in C# is crucial to writing effective and efficient code, particularly in complex scenarios. Remember to follow best practices and keep an eye out for pitfalls, and your code will be more robust, maintainable, and well-organized.

Conclution

Marking a conversion as implicit or explicit must strictly meet the criteria of whether there is a risk of information loss. It may be the case that today you consider the loss of information that occurs to be negligible, but that at some point it is not.

If you have marked the conversion as implicit, anyone who uses it directly assumes that there is no information loss.

If there is later and the failure is in that conversion, it can be a big headache, even more so if the code is part of a library and the person who uses it cannot see the code. From ByteHide we recommed you always think about it before defining the conversion. 🤗

You May Also Like

Sign up For Our Newsletter

Weekly .NET Capsules: Short reads for busy devs.

  • NLatest .NET tips and tricks
  • NQuick 5-minute reads
  • NPractical code snippets
.