8 Late Binding in C# and .NET
Late binding is about deferring decisions about which concrete implementation to use until runtime (or configuration time), rather than hardcoding those decisions at compile time. This gives you flexibility to swap implementations without rebuilding your application.
8.1 The Core Concept
Think of it like this:
COMPILE TIME (Early Binding)
┌──────────────────────────────────────┐
│ Application Code │
│ ↓ │
│ Hardcoded: new SqlServerRepository()│
│ ↓ │
│ SQL Server only │
└──────────────────────────────────────┘
Problem: Must recompile to change database!
RUNTIME (Late Binding)
┌─────────────────────────────────────┐
│ Application Code │
│ ↓ │
│ Uses: IRepository interface │
│ ↓ │
│ Configuration decides at runtime: │
│ - SqlServerRepository, OR │
│ - OracleRepository │
└─────────────────────────────────────┘
Benefit: Change via config file, no recompile!
8.2 C# Example: Database Abstraction
Let’s build the database example from your excerpt:
8.2.1 Step 1: Define the Interface
// IRepository.cs
public interface IRepository
{
void SaveData(string data);
string GetData(int id);
}8.2.2 Step 2: Create Multiple Implementations
// SqlServerRepository.cs
public class SqlServerRepository : IRepository
{
public void SaveData(string data)
{
Console.WriteLine($"Saving to SQL Server: {data}");
// Actual SQL Server code here
}
public string GetData(int id)
{
return $"Data from SQL Server with ID: {id}";
}
}
// OracleRepository.cs
public class OracleRepository : IRepository
{
public void SaveData(string data)
{
Console.WriteLine($"Saving to Oracle: {data}");
// Actual Oracle code here
}
public string GetData(int id)
{
return $"Data from Oracle with ID: {id}";
}
}8.2.3 Step 3: Application Code (Depends on Interface Only)
// DataService.cs
public class DataService
{
private readonly IRepository _repository;
// Constructor injection - doesn't know which implementation!
public DataService(IRepository repository)
{
_repository = repository;
}
public void ProcessData()
{
_repository.SaveData("Patient scan data");
var data = _repository.GetData(123);
Console.WriteLine(data);
}
}8.2.4 Step 4: Late Binding via Configuration
Option A: Using appsettings.json
// appsettings.json
{
"DatabaseProvider": "SqlServer" // or "Oracle"
}Option B: Binding at Application Startup
// Program.cs
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
var services = new ServiceCollection();
// Late binding: Decision made at runtime based on config
string provider = configuration["DatabaseProvider"];
if (provider == "SqlServer")
{
services.AddScoped<IRepository, SqlServerRepository>();
}
else if (provider == "Oracle")
{
services.AddScoped<IRepository, OracleRepository>();
}
services.AddScoped<DataService>();
var serviceProvider = services.BuildServiceProvider();
// Use the service
var dataService = serviceProvider.GetService<DataService>();
dataService.ProcessData();8.3 Flow Diagram
┌──────────────────────────────────────────────────────┐
│ Compile Time │
│ ──────────────────────────────────────── │
│ • Interface IRepository is defined │
│ • Multiple implementations exist │
│ • DataService depends on IRepository │
│ • NO decision about which implementation │
└──────────────────────────────────────────────────────┘
│
│ Build & Deploy
↓
┌──────────────────────────────────────────────────────┐
│ Deployment Time / Runtime │
│ ──────────────────────────────────────── │
│ • Read appsettings.json │
│ • See DatabaseProvider = "SqlServer" │
│ • Bind IRepository → SqlServerRepository │
│ • Inject into DataService │
└──────────────────────────────────────────────────────┘
│
↓
┌──────────────────────────────────────────────────────┐
│ To Switch Databases │
│ ──────────────────────────────────────── │
│ 1. Edit appsettings.json │
│ DatabaseProvider: "Oracle" │
│ 2. Restart application │
│ 3. NO RECOMPILATION NEEDED! ✓ │
└──────────────────────────────────────────────────────┘
8.4 VS Code Setup
In VS Code for .NET, you’d structure your project like this:
MyProject/
├── Program.cs (startup & DI configuration)
├── appsettings.json (runtime configuration)
├── Interfaces/
│ └── IRepository.cs
├── Implementations/
│ ├── SqlServerRepository.cs
│ └── OracleRepository.cs
└── Services/
└── DataService.cs
Run with:
dotnet runChange database by editing appsettings.json and restarting—no recompile!
8.5 Real-World Medical Imaging Example
For your radiology work, imagine:
// Late binding for different PACS systems
public interface IPacsClient
{
void UploadDicomImage(byte[] imageData);
byte[] DownloadDicomImage(string studyId);
}
// Implementations
public class VnaPacsClient : IPacsClient { ... }
public class GePacsClient : IPacsClient { ... }
public class PhilipsPacsClient : IPacsClient { ... }
// In appsettings.json
{
"PacsProvider": "VnaPacs" // Switch hospitals? Just change config!
}Different hospitals use different PACS systems. With late binding, your radiology AI application can work with any PACS by just changing the configuration file—no code changes needed!