Skip to Content
Course content

64: Conversion Operators: Implicit and Explicit

Click on the "Edit" button in the top corner of the screen to edit your slide content.

A lot of developers I've mentored assume that casting—the act of telling C# "treat this thing as that type"—is a built-in magic trick reserved for primitive types like int and double, or for moving up and down an inheritance hierarchy. They think that if they've built a custom class or struct, they are stuck writing "converter" methods like ToDecimal() or FromDouble() for the rest of eternity.

Casting is only for built-in types and inheritance

Let's look at why that's a limiting way to think. Imagine you have a Money struct. You want to be able to use it in a calculation with a standard decimal without calling a method every single time. If you try this without conversion operators, it fails:

public struct Money 
{ 
    public decimal Amount { get; set; } 
}

Money wallet = new Money { Amount = 10.50m };
decimal total = wallet; // CS0029: Cannot implicitly convert type 'Money' to 'decimal'

The compiler doesn't care that Money only contains a decimal. To the C# compiler, these are two completely different types. You might be tempted to just add a GetAmount() method, but that clutters your business logic with "plumbing" calls. It makes your code feel like you're fighting the language rather than using it.

Teaching C# how to treat your objects as other types

This is where implicit and explicit operators come in. You can actually define the rules for how your custom type transforms into another type. I like to think of it as defining a "bridge" between two types.

An implicit conversion is a bridge that the compiler is allowed to cross automatically. You use this when the conversion is "safe"—meaning there is no risk of data loss or an exception. An explicit conversion is a bridge that requires a manual "push" (a cast), which signals to other developers that something potentially risky is happening.

Let's fix our Money struct. We'll make it implicit to convert Money to decimal (since that's always safe), but explicit to convert a decimal back into Money (because we want to be intentional about creating a value object):

public struct Money 
{ 
    public decimal Amount { get; }

    public Money(decimal amount) => Amount = amount;

    // Implicit: No cast needed. Safe and seamless.
    public static implicit operator decimal(Money money) => money.Amount;

    // Explicit: Requires (Money)cast. Intentional.
    public static explicit operator Money(decimal amount) => new Money(amount);
}

// Now this works automatically:
Money wallet = new Money(10.50m);
decimal total = wallet; 

// This requires a cast:
decimal rawValue = 20.00m;
Money payment = (Money)rawValue; 

Notice the syntax: public static [implicit/explicit] operator [TargetType]([SourceType] value). It's a bit wordy, but it's powerful. I generally suggest using implicit only when the conversion is truly lossless. If you're converting a double to an int, or a User object to a string, go explicit. You want the person reading your code to see that cast and think, "Okay, something is being transformed here," rather than wondering why a type suddenly changed mid-sentence.

  • Implicit operators make your API feel cleaner and more natural.
  • Explicit operators protect you from accidental data loss or unexpected type changes.
  • Both must be public static.



📋 Practical Task

Implementing Weight-to-Double Conversion Logic

You are building a fitness tracking application. You have a Weight struct that stores a value in kilograms. To ensure the rest of the app can perform calculations easily, you need to implement conversion operators.

Your Task:

  • Create a struct Weight with a private double _kilograms field and a constructor to set it.
  • Implement an implicit operator that allows a Weight object to be treated as a double.
  • Implement an explicit operator that allows a double to be converted into a Weight object.
  • In your Main method, demonstrate both: assign a Weight object to a double variable without a cast, and assign a double to a Weight variable using a cast.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.