Interfaces
Interfaces define contracts — method signatures without implementation (until default interface methods).
Introduction
Interfaces define contracts — method signatures without implementation (until default interface methods). A class implements multiple interfaces: IDisposable, IComparable, custom domain ports. ASP.NET Core action methods, EF configurations, and middleware all implement interfaces.
C# 8+ default interface methods allow evolving interfaces without breaking implementers — used sparingly. Interviewers ask interface vs abstract class, explicit implementation, and generic variance.
Interfaces are the primary extension point in testable .NET architecture.
The story
A warehouse inventory system tracks products that need audit metadata — when each record was created and last modified. The same IAuditable interface applies to products, shipments, and purchase orders, while a generic IEntityRepository<T> provides consistent CRUD operations for any entity type.
Understanding the topic
Key concepts
- interface declares contract; class/struct implements.
- Multiple interface implementation allowed.
- Explicit implementation: InterfaceName.Method() hides from public API.
- Generic interfaces: IRepository
, IComparable . - Covariance out T; contravariance in T on delegates/interfaces.
- Default interface members (D# 8) optional implementation.
classDiagramclass IRepository~T~ {<<interface>>+GetById(id)+Save(entity)}class EfRepository~T~ {+GetById(id)+Save(entity)}IRepository~T~ <|.. EfRepository~T~
Step-by-step explanation
- Class lists interfaces after base class: class X : Base, IA, IB.
- Compiler verifies all members implemented.
- Interface reference only exposes interface members.
- DI registers Type pairs for interface resolution.
- Mock frameworks implement interfaces in tests dynamically.
- Sealed interface implementations prevent further override of behavior.
Practical code example
Multiple interfaces — auditable entity and repository:
namespace TechLearningPro.Interfaces;public interface IAuditable{DateTimeOffset CreatedAt { get; }DateTimeOffset? ModifiedAt { get; }}public interface IEntityRepository<T> where T : class{Task<T?> GetAsync(Guid id, CancellationToken ct);Task InsertAsync(T entity, CancellationToken ct);}public sealed class Product : IAuditable{public Guid Id { get; init; }public string Name { get; init; } = "";public DateTimeOffset CreatedAt { get; init; } = DateTimeOffset.UtcNow;public DateTimeOffset? ModifiedAt { get; private set; }public void Touch() => ModifiedAt = DateTimeOffset.UtcNow;}
Line-by-line code explanation
interface IAuditabledefines audit fields every tracked entity must expose.DateTimeOffset CreatedAt { get; }records when the entity was first saved.DateTimeOffset? ModifiedAt { get; }is nullable until the first update occurs.interface IEntityRepository<T> where T : classconstrains T to reference types only.Task<T?> GetAsync(Guid id, ...)retrieves a single entity by primary key.Task InsertAsync(T entity, ...)adds a new entity through the repository contract.class Product : IAuditableimplements the audit interface alongside product-specific properties.CreatedAt { get; init; } = DateTimeOffset.UtcNowstamps creation time at initialization.ModifiedAt { get; private set; }can only change through class methods likeTouch().Touch() => ModifiedAt = DateTimeOffset.UtcNowupdates the modification timestamp in one place.
Key takeaway: IAuditable cross-cuts entities. Generic IEntityRepository
Real-world use
Where you'll use this in production
- ASP.NET Core middleware implementing IMiddleware.
- IDisposable for resource cleanup using patterns.
- Plugin host loading IPlugin from assemblies.
- Test mocks of IEmailSender in unit tests.
Best practices
- One interface per role — segregate large contracts.
- Suffix domain interfaces meaningfully — IOrderService not IOrderManager2.
- Implement IDisposable correctly when holding unmanaged resources.
- Prefer interface injection in constructors.
- Avoid marker interfaces without behavior — use attributes if needed.
Common mistakes
- Fat interface forcing empty NotImplementedException stubs.
- Public class exposing explicit implementation unnecessarily.
- Implementing IDisposable without suppress finalize pattern when needed.
- Changing interface breaking all implementers — use extension or new interface.
Advanced interview questions
Interview Prep
Practice concise answers, then expand each card for the explanation.
1BeginnerQuestionCan struct implement interface?+
Answer
2BeginnerQuestionInterface vs abstract class?+
Answer
3IntermediateQuestionExplicit interface implementation why?+
Answer
4IntermediateQuestionIEnumerable covariance?+
Answer
5AdvancedQuestionEvolve published interface without breaking implementers?+
Answer
Summary
Interfaces define contracts; classes implement multiple. Generic and auditable interfaces cross-cut enterprise domains. DI and testing rely heavily on interface abstractions. Keep interfaces small and role-specific. Next: arrays — first collection type.