C#
operator overloading
interface-based programming
object-oriented programming
software development

Operator Overloading with Interface-Based Programming in C

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

Operator overloading and interface-based design solve different problems in C#. Interfaces define contracts and substitution points, while overloaded operators are implemented only on concrete types. The usual pattern is to design around interfaces for abstraction and testing, then place operators on immutable value-like implementations where the semantics are obvious.

Operators Belong to Concrete Types

C# does not let an interface define operator implementation in the same practical way that a class or struct does for normal domain models. That means an operator such as + is attached to a concrete type, even if the rest of the system depends on an interface.

A common example is a money type.

csharp
1public interface IAmount
2{
3    decimal Value { get; }
4    string Currency { get; }
5}
6
7public sealed class Money : IAmount
8{
9    public decimal Value { get; }
10    public string Currency { get; }
11
12    public Money(decimal value, string currency)
13    {
14        Value = value;
15        Currency = currency;
16    }
17
18    public static Money operator +(Money left, Money right)
19    {
20        if (left.Currency != right.Currency)
21            throw new InvalidOperationException("Currency mismatch");
22
23        return new Money(left.Value + right.Value, left.Currency);
24    }
25}

The interface tells the rest of the program what an amount looks like. The concrete Money type provides the arithmetic behavior.

Why Immutability Matters

Operator overloading is easiest to reason about when the operands behave like values instead of mutable objects. If a + b mutates a, the code becomes surprising immediately.

That is why overloaded operators are usually best on:

  • immutable classes
  • immutable structs used carefully
  • domain types with clear mathematical meaning

For domain objects with identity, lifecycle state, or side effects, operator overloading usually makes the code less clear rather than more expressive.

Keep Method and Operator Semantics Aligned

If you provide both a normal method and an operator, they should mean the same thing.

csharp
1public sealed class Money : IAmount
2{
3    public decimal Value { get; }
4    public string Currency { get; }
5
6    public Money(decimal value, string currency)
7    {
8        Value = value;
9        Currency = currency;
10    }
11
12    public Money Add(Money other) => this + other;
13
14    public static Money operator +(Money left, Money right)
15    {
16        if (left.Currency != right.Currency)
17            throw new InvalidOperationException("Currency mismatch");
18
19        return new Money(left.Value + right.Value, left.Currency);
20    }
21}

If Add and + behave differently, the type becomes harder to trust. The operator should not be a shortcut for a different rule.

Use Interfaces in the Service Layer

The service layer can still depend on interfaces even when operators live on concrete types.

csharp
1public static class InvoiceMath
2{
3    public static Money ApplyTax(Money amount, decimal rate)
4    {
5        var tax = new Money(amount.Value * rate, amount.Currency);
6        return amount + tax;
7    }
8}

In other words, interface-based design and operator overloading are not opposites. They just operate at different levels of the model.

Interfaces help with composition, dependency inversion, and testing. Operators help with local expressiveness when the concrete type really behaves like a value.

Equality Must Stay Consistent

If you overload operators such as == and !=, they must agree with Equals and GetHashCode.

csharp
1public sealed class Money : IEquatable<Money>
2{
3    public decimal Value { get; }
4    public string Currency { get; }
5
6    public Money(decimal value, string currency)
7    {
8        Value = value;
9        Currency = currency;
10    }
11
12    public bool Equals(Money? other) =>
13        other is not null && other.Value == Value && other.Currency == Currency;
14
15    public override bool Equals(object? obj) => Equals(obj as Money);
16    public override int GetHashCode() => HashCode.Combine(Value, Currency);
17
18    public static bool operator ==(Money? left, Money? right) => Equals(left, right);
19    public static bool operator !=(Money? left, Money? right) => !Equals(left, right);
20}

If equality is inconsistent, collections, caching, and comparisons start behaving unpredictably.

Common Pitfalls

The most common mistake is expecting an interface to carry the full operator behavior. In practice, the operator still lives on the concrete implementation, so callers either need that concrete type or a method-based abstraction.

Another issue is overloading operators for types that do not have obvious mathematical semantics. + on money is natural. + on a complex mutable service object is usually not.

Teams also often skip invariant checks. A money addition operator that ignores currency mismatch is concise but wrong.

Finally, do not add operator overloads only because the language allows them. Use them when they make the code more readable for everyone, not just for the type author.

Summary

  • Interfaces define contracts, but operators are implemented on concrete types.
  • Operator overloading works best on immutable, value-like domain types.
  • Keep method-based and operator-based APIs semantically identical.
  • Enforce domain invariants inside every overloaded operator.
  • Use operators only when the meaning is obvious and stable to readers.

Related reading
Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.