Interfaces and Generics
Interfaces and Generics in C#
Interfaces An interface defines a contract. Any class or struct can implement it:
interface IDrawable { void Draw(); }
class Circle : IDrawable { public void Draw() { … } }C# 8+ allows default interface methods.
Generic types Generics parameterise types and methods for reuse without sacrificing type safety:
class Stack<T> { … }
var s = new Stack<int>();where T : constraints
Restrict what types can be used as the type parameter:
where T : class— reference typewhere T : struct— value typewhere T : new()— has a parameterless constructorwhere T : IComparable<T>— implements an interface
List<T> and Dictionary<K,V>
Generic collections from System.Collections.Generic provide type-safe data structures without boxing overhead.
Key points:
- A class can implement multiple interfaces.
- Prefer
List<T>overArrayList(which uses object and requires casting). - Use
Dictionary<K,V>for O(1) key-based lookups.
Code Examples
using System;
using System.Collections.Generic;
interface IRepository<T> {
void Add(T item);
IEnumerable<T> GetAll();
}
class InMemoryRepository<T> : IRepository<T> {
private readonly List<T> _items = new();
public void Add(T item) => _items.Add(item);
public IEnumerable<T> GetAll() => _items;
}
class Program {
static void Main() {
var repo = new InMemoryRepository<string>();
repo.Add("Alice");
repo.Add("Bob");
repo.Add("Charlie");
foreach (var name in repo.GetAll())
Console.WriteLine(name);
}
}A generic repository can hold any type. The interface contract ensures consistent behaviour regardless of T.
using System;
using System.Collections.Generic;
class Program {
static void Main() {
var scores = new Dictionary<string, int> {
["Alice"] = 95,
["Bob"] = 80
};
scores["Charlie"] = 90;
foreach (var (name, score) in scores)
Console.WriteLine($"{name}: {score}");
Console.WriteLine($"Has Dave: {scores.ContainsKey("Dave")}");
Console.WriteLine($"Alice: {scores.GetValueOrDefault("Alice")}");
var evens = new List<int>();
for (int i = 2; i <= 10; i += 2) evens.Add(i);
Console.WriteLine(string.Join(", ", evens));
}
}Dictionary<K,V> provides O(1) lookups. Tuple deconstruction in foreach makes key-value iteration concise.
Quick Quiz
1. What does `where T : new()` constraint require?
2. Why prefer `List<T>` over `ArrayList`?
Was this lesson helpful?