DEV Community

Dev Leader
Dev Leader

Posted on • Originally published at devleader.ca

Implicit Operators – Clean Code Secrets Or Buggy Nightmare?

Welcome to the world of implicit operators in C#! Implicit operators are a powerful feature of the C# language that have the ability to make our code more readable and expressive. In the wrong hands, they can allow for some really tricky behavior that’s hard to notice unless you go investigating. Implicit operators can allow us to define custom conversions that occur without explicit casting, and thus eliminate some clunky syntax when we want to convert between types. This might seem like a small thing, but it can have a big impact on the readability and maintainability of our code.

Implicit operators are defined using the implicit keyword and can be used to create a method that converts one type to another. Two key rules of implicit operators are that they should not throw exceptions and should not lose information, as the conversion is done automatically by the compiler. This is because the compiler needs to be able to guarantee that the conversion can always succeed without any potential for data loss or exceptions.

Understanding Implicit Operators

Implicit operators are special methods we can define in our classes to allow for automatic conversion to another type. They are defined using the implicit keyword. This keyword is used to modify the operator keyword in the method signature, indicating that the operator will be applied implicitly.

Here’s a simple example:

public readonly record struct Meter
{
    public double Length { get; init; }

    public static implicit operator Meter(double length)
    {
        return new Meter { Length = length };
    }
}

// Usage
Meter meter = 10.0;
Console.WriteLine(meter); // Meter { Length = 10 }
Enter fullscreen mode Exit fullscreen mode

In this example, we’ve defined an implicit operator that allows us to convert a double to a Meter object. This is done without any explicit casting or conversion in the code, hence the term “implicit operator”. The compiler automatically applies the operator when it’s needed, and we don’t need to explicitly cast with (double) or (meter) in front of our variables.

The Power of Implicit Operators

Implicit operators can be incredibly powerful. They allow us to create code that is more expressive and easier to read. By defining implicit operators, we can create types that feel like a natural part of the language, rather than something that’s been bolted on. This can be a popular solution for looking into strongly typed identifiers as well when you want to create types that naturally fit into the domain you’re working in.

For example, consider a Money type. Without implicit operators, working with a Money type might look something like this:

Money m = new Money(10.0m);
decimal amount = m.Amount;
Enter fullscreen mode Exit fullscreen mode

But with implicit operators, we can make this code much more natural and intuitive:

Money m = 10.0m;
decimal amount = m;
Enter fullscreen mode Exit fullscreen mode

This might seem like a small change, but it can make a big difference in the readability of our code. And given that we, as software developers, spend much of our time reading code compared to writing it… Readability should be optimized for!

Companion Video for Implicit Operators

Practical Applications of Implicit Operators

Implicit operators can be used to improve the readability of your code and to create more intuitive APIs. They are particularly useful when working with domain-specifics or when you want to provide a simple interface for working with complex types. I even used them for creating custom return types that make my exception handling much easier!

For example, you could define implicit operators for a Money type that allow you to work with money values as if they were numbers:

public readonly record struct Money
{
    public decimal Amount { get; init; }

    public static implicit operator Money(decimal amount)
    {
        return new Money { Amount = amount };
    }

    public static implicit operator decimal(Money money)
    {
        return money.Amount;
    }
}

// Usage
Money money = 10.0m;
decimal amount = money;
Enter fullscreen mode Exit fullscreen mode

In this example, we can assign a decimal to a Money object and vice versa, making the Money type feel more like a natural part of the domain you’re working in.

Advanced Usage of Implicit Operators

Want to read more about advanced usage and some of the pitfalls and considerations? Check out the full post on implicit operators on Dev Leader!

If you enjoy these blog posts, consider subscribing to my weekly newsletter for a quick 5-minute read every Saturday! I summarize C# and software engineering content for the week along with some other resources and community highlights!

Top comments (0)