Interfaces
C# interfaces vs Python protocols and ABCs
Introduction
In this lesson, you'll learn about interfaces in C#. Coming from Python, you already have a foundation for understanding this concept. We'll build on that knowledge while highlighting the key differences.
In Python, you're familiar with c# interfaces vs python protocols and abcs.
C# has its own approach to c# interfaces vs python protocols and abcs, which we'll explore step by step.
The C# Way
Let's see how C# handles this concept. Here's a typical example:
// Interface: contract only (or with default implementations)
public interface IDrawable
{
void Draw();
double Area();
// Default method (C# 8+) — like Python concrete method in ABC
string Describe() => $"Area: {Area()}";
}
// Explicit implementation
public class Circle : IDrawable
{
public double Radius { get; }
Circle(double r) => Radius = r;
public void Draw() => Console.WriteLine("O");
public double Area() => Math.PI * Radius * Radius;
}
// Multiple interfaces
public class Ring : IDrawable, IComparable<Ring>
{
public void Draw() { }
public double Area() { return 0; }
public int CompareTo(Ring? other) { return 0; }
}
// Explicit interface implementation (avoids name clashes)
public class Widget : IFoo, IBar
{
void IFoo.DoThing() { } // only accessible via IFoo reference
void IBar.DoThing() { }
}
// Polymorphism via interface type
void Render(IDrawable d) => d.Draw();
Render(new Circle(5));Comparing to Python
Here's how you might have written similar code in Python:
from typing import Protocol
from abc import ABC, abstractmethod
# Protocol (structural — like Go interfaces)
class Drawable(Protocol):
def draw(self) -> None: ...
def area(self) -> float: ...
# Any class with draw() + area() satisfies Drawable
class Circle:
def draw(self) -> None: print("O")
def area(self) -> float: return 3.14 * self.r ** 2
# Abstract base class (nominal — must inherit)
class Shape(ABC):
@abstractmethod
def area(self) -> float: ...
def describe(self) -> str: # concrete default
return f"Area: {self.area()}"
class Rectangle(Shape):
def area(self) -> float: return self.w * self.h
# Can't mix — Protocol is structural, ABC is nominal
def render(d: Drawable) -> None:
d.draw()You may be used to different syntax or behavior.
C# interfaces are nominal — classes must explicitly state 'implements IXxx'
You may be used to different syntax or behavior.
Python Protocols are structural (duck typing); ABCs are nominal like C# interfaces
You may be used to different syntax or behavior.
Default interface methods (C# 8+) allow adding methods without breaking implementations
You may be used to different syntax or behavior.
A C# class can implement multiple interfaces (no multiple class inheritance)
You may be used to different syntax or behavior.
Explicit interface implementation resolves method name conflicts between interfaces
Step-by-Step Breakdown
1. Declare and Implement
C# interfaces define method/property signatures. Unlike Python Protocol, implementing classes must explicitly declare the interface.
class Drawable(Protocol):
def draw(self) -> None: ...
class Circle: # implicitly satisfiesinterface IDrawable { void Draw(); }
class Circle : IDrawable // explicit
{
public void Draw() => Console.WriteLine("O");
}2. Multiple Interfaces
A class can implement multiple interfaces separated by commas. This is C#'s way to achieve multiple inheritance of behavior.
class Shape(Drawable, Serializable): ... # multiple baseclass Shape : IDrawable, ISerializable
{
public void Draw() { }
public void Serialize(Stream s) { }
}3. Default Methods
C# 8+ allows default method bodies in interfaces, like Python's concrete methods in ABC. Implementing classes can override them.
class Shape(ABC):
def describe(self): return f"Area:{self.area()}"interface IShape {
double Area();
string Describe() => $"Area: {Area()}"; // default
}4. Interface as Type
Program to interfaces, not concrete types. Assign any implementing class to an interface variable — enables polymorphism and testability.
def process(shape: Drawable) -> None:
shape.draw()void Process(IDrawable d) => d.Draw();
// Anywhere:
IDrawable d = new Circle(5);
d = new Rectangle(3, 4); // can reassignCommon Mistakes
When coming from Python, developers often make these mistakes:
- C# interfaces are nominal — classes must explicitly state 'implements IXxx'
- Python Protocols are structural (duck typing); ABCs are nominal like C# interfaces
- Default interface methods (C# 8+) allow adding methods without breaking implementations
Key Takeaways
- C# interfaces are nominal — explicit 'implements'; Python Protocols are structural
- A class can implement multiple interfaces — C#'s multiple inheritance mechanism
- Default methods (C# 8+) add concrete implementations to interfaces
- Program to interfaces: accept IDrawable, not Circle — enables polymorphism and easy testing