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:
- Chained Accessors
user.GetProfile().GetSettings().EnableDarkMode(); // ❌
- Returning Internal Objects
public Engine GetEngine(); // ❌ exposes internal structure
- 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!