Understanding the Law of Demeter in C#: With Clean Code and Diagrams

We, as software developers, always seek to write neat, easy-to-maintain and expandable code. Many other design advice can support this effort, but the Law of Demeter (LoD) is widely ignored by developers. Putting this philosophy into use in a language like C# can really cut down on complexity and make the code much easier to read.

This post will explain the Law of Demeter in C# using simple words, highlight its role in C# and share examples along with a diagram. If you are new to the topic or need a refresher, this guide will help you use the Law of Demeter in your projects.

📘 What is the Law of Demeter?

The Law of Demeter, also called the Principle of Least Knowledge, encourages each unit in your code (like a class or method) to have limited knowledge about other units. In simpler terms:

“Only talk to your immediate friends.”

This means a method should only invoke methods on:

  • The object itself
  • Objects passed in as parameters
  • Objects it creates
  • Its direct instance variables

By sticking to these boundaries, your code becomes loosely coupled, which makes it easier to test, modify, and extend.

🤔 Why Should C# Developers Care?

In C#, it’s easy to fall into the trap of chaining methods or exposing deep object hierarchies. But that often leads to fragile code.

Let’s say a small change in one class requires you to touch multiple parts of your application. That’s a sign your components are too tightly coupled.

By applying the Law of Demeter:

  • You reduce dependencies
  • Your code becomes more modular
  • Maintenance becomes simpler
  • Tests are easier to write

Let’s look at what this looks like in C#.

🚫 Bad Example: Breaking the Law of Demeter in C#

Here’s some code that violates the Law of Demeter:

public class Engine
{
    public void Start() => Console.WriteLine("Engine started");
}

public class Car
{
    private Engine _engine = new Engine();

    public Engine GetEngine() => _engine;
}

public class Driver
{
    public void StartCar(Car car)
    {
        car.GetEngine().Start(); // ❌ Violates Law of Demeter
    }
}

What’s wrong here?

The Driver class is reaching into Car to access the Engine. It now knows about both Car and its internal Engine, which introduces unnecessary coupling.

✅ Good Example: Following the Law of Demeter in C#

Let’s refactor the code to follow the principle:

public class Engine
{
    public void Start() => Console.WriteLine("Engine started");
}

public class Car
{
    private Engine _engine = new Engine();

    public void Start() => _engine.Start();
}

public class Driver
{
    public void StartCar(Car car)
    {
        car.Start(); // ✅ Follows Law of Demeter
    }
}

Now, Driver interacts directly with Car only. The internal working of the Car (like having an Engine) is hidden. This encapsulation makes future changes easier and safer.

🔍 Diagram: Law of Demeter Visualised

Let’s represent this visually:

❌ Violating the Law:

[Driver] --> [Car] --> [Engine] --> Start()

✅ Respecting the Law:

[Driver] --> [Car.Start()]
             |
         [Engine]

With proper abstraction, we talk only to the object we need—no deep diving through object graphs.

⚠️ Common Violations in C#

Here are patterns to watch out for:

  1. Chained Accessors
user.GetProfile().GetSettings().EnableDarkMode(); // ❌
  1. Returning Internal Objects
public Engine GetEngine(); // ❌ exposes internal structure
  1. Excessive Dependency Injection
    Sometimes injecting too many services or dependencies into a class can hint at LoD violations.

🧰 Tools to Detect Law of Demeter Violations

  • Roslyn Analyzers: You can write custom Roslyn rules to detect method chaining or nested object access.
  • NDepend: Provides advanced code metrics and rules for architectural enforcement.
  • ReSharper: Alerts you when methods are overly dependent on inner objects.

🎯 When Breaking the Rule is Okay

Fluent APIs (like LINQ or Entity Framework) often chain methods by design. This doesn’t mean they violate the principle incorrectly—they’re structured and well-understood.

For example:

var users = dbContext.Users.Where(u => u.IsActive).ToList();

This is acceptable because you’re working with a controlled abstraction. The key is to understand the trade-offs and avoid unnecessary exposure of internal structure.

🛠️ Practice: Refactor This

Here’s a snippet that breaks the Law of Demeter:

public class Library
{
    public Book GetBook() => new Book();
}

public class Book
{
    public string GetTitle() => "Clean Code";
}

public class Reader
{
    public void ShowTitle(Library library)
    {
        Console.WriteLine(library.GetBook().GetTitle());
    }
}

✅ Refactored:

public class Library
{
    private Book _book = new Book();

    public string GetBookTitle() => _book.GetTitle();
}

public class Reader
{
    public void ShowTitle(Library library)
    {
        Console.WriteLine(library.GetBookTitle());
    }
}

Now the Reader only interacts with the Library and has no idea how titles are fetched.

🧠 Summary

The Law of Demeter is simple but powerful. In C#, following this principle means:

  • Avoid chaining multiple object calls
  • Hide internal structures
  • Design methods to only interact with closely related objects

This helps your codebase become more maintainable, testable, and easier to understand.

Remember: talk to friends, not strangers.

By applying the Law of Demeter, you’re writing smarter C# code that will stand the test of time.

🔗 Further Reading

Need help refactoring your code to follow this principle? Drop your code snippet in the comments, and let’s work through it together!

Leave a Comment