Interfaces define the "Contract" of your application. While they used to be simple lists of method names, modern C# has empowered interfaces with Default Implementations and Static Abstract Members, blurring the line between Interface and Abstract Class.
Never create "Fat Interfaces." It’s better to have 5 tiny, specific interfaces than one giant interface that forces a class to implement methods it doesn't need.
// GOOD
public interface IReader { string Read(); }
public interface IWriter { void Write(string s); }
// A class can then choose exactly what to implement
public class ReadOnlyFile : IReader { ... }
What if you have an interface used by 50 classes, and you want to add a new method? In the past, you would "break" all 50 classes. Now, you can provide a default "fallback" logic directly in the interface.
public interface ILogger
{
void Log(string msg);
// Classes do NOT have to implement this!
void LogError(string msg) => Log($"[ERROR] {msg}");
}
The most advanced feature in modern .NET: Generic Math. You can now define static methods in an interface that the implementing class MUST override. This allows for powerful generic algorithms.
public interface IMonoid<T> where T : IMonoid<T>
{
static abstract T operator +(T left, T right);
}
Q: "When should I use an Interface versus an Abstract Class?"
Architect Answer: "The decision should be based on 'Is-a' vs 'Can-do.' Use an **Abstract Class** when there is a strong hierarchical relationship (`Is-a`); for example, a `Vehicle` base class for `Car`. Abstract classes let you share internal state (private fields). Use an **Interface** when you want to define a capability (`Can-do`); for example, `IDisposable` (Can be disposed) or `IPrintable` (Can be printed). Crucially, a C# class can only inherit from ONE abstract class, but it can implement INFINITE interfaces. Interfaces are the primary tool for decoupling your high-level architecture from low-level implementation details."