Why Use Collections?
Arrays have fixed sizes—once allocated, their length cannot change. This rigidity leads to either wasted memory (if oversized) or the need for code changes when requirements evolve. Collections, in contrast, dynamically resize as elements are added or removed.
Generic List<T>
List<T> is a strongly typed collection from the System.Collections.Generic namespace. The type parameter T enforces that all elements must be of the same type, eliminating the need for casting upon retrieval.
Common operations include:
Add(T item)– appends an elementRemove(T item)– removes the first matching elementCount– gets the number of elements- Iteration via
foreach
Its primary advantage is compile-time type safety.
Dictionary<K, V>
Dictionary<K, V> stores key-value pairs with O(1) average lookup time. Like List<T>, it is generic, avoiding boxing/unboxing and ensuring type safety at compile time. Keys must be unique; attempting to add a duplicate key throws an exception.
Default Sorting with List<T>
For primitive types (e.g., int, string), list.Sort() works out of the box. For custom types, the class must implement IComparable<T>:
public int CompareTo(Student other)
{
return this.StuId.CompareTo(other.StuId); // ascending by ID
}
This approach supports only one default sort order per type.
Dynamic Sorting with IComparer<T>
When multiple sort criteria are needed (e.g., sort by name ascending or age descending), implement IComparer<T> in separate classes:
class AgeAscending : IComparer<Student>
{
public int Compare(Student x, Student y) => x.Age.CompareTo(y.Age);
}
class NameDescending : IComparer<Student>
{
public int Compare(Student x, Student y) => y.StuName.CompareTo(x.StuName);
}
Pass an instance to Sort():
list.Sort(new AgeAscending());
This replaces the default IComparable<T> behavior entirely.
LINQ-Based Sorting
LINQ provides a fluent syntax for sorting without modifying the original list:
var byAgeDesc = list.OrderByDescending(s => s.Age).ToList();
var byNameAsc = list.OrderBy(s => s.StuName).ToList();
These methods return new lists and support chaining (e.g., ThenBy).
Generics Deep Dive
Generics defer type specification until instantiation, enabling reusable, type-safe code. Supported constructs include generic classes, methods, interfaces, and delegates.
Constraints
Use where clauses to restrict allowable types:
where T : class– reference typewhere T : struct– value typewhere T : new()– must have a parameterless constructorwhere T : BaseClass, IInterface– multiple constraints (must be compatible)
Constraints grant access to members of the constrained type while enforcing correctness.
Covariance and Contravariance
- Covariance (
out): Allows assignment from more derived to less derived types in output positions (e.g.,IEnumerable<Sparrow>→IEnumerable<Bird>). - Contravariance (
in): Permits assignment from less derived to more derived types in input positions (e.g.,Action<Bird>→Action<Sparrow>).
These features enible flexible generic interface usage while preserving type safety.
Generic Caching
Static generic types (e.g., static class Cache<T>) maintain separate state per T, offering high-performance caching without manual management—but memory persists for the application lifetime.
Core Data Structures
Arrays vs. Lists
| Type | Element Type | Size | Boxing? | Notes |
|---|---|---|---|---|
T[] |
Homogeneous | Fixed | No | Fast indexing |
ArrayList |
Heterogeneous | Dynamic | Yes | Obsolete; use List<T> |
List<T> |
Homogeneous | Dynamic | No | Preferred dynamic array |
Linked Structures
LinkedList<T>: Doubly linked; efficient insert/delete at ends, no indexing.Queue<T>: FIFO;Enqueue,Dequeue,Peek.Stack<T>: LIFO;Push,Pop,Peek.
Thread-safe variants: ConcurrentQueue<T>, ConcurrentStack<T>.
Sets
HashSet<T>: Unordered, unique elements; supports set operations (union, intersect, etc.).SortedSet<T>: Ordered, unique elements; usesIComparer<T>for sorting.
Key-Value Stores
| Type | Ordering | Thread-Safe? | Notes |
|---|---|---|---|
Hashtable |
No | Yes* | Non-generic; legacy |
Dictionary<K,V> |
Insertion | No | Preferred generic map |
SortedDictionary |
Key | No | Tree-based; slower inserts |
SortedList |
Key | No | Array-backed; memory-efficient |
ConcurrentDictionary<K,V> provides thread-safe operations.
Key Interfaces
IEnumerable<T>: Enablesforeach; base for all collections.ICollection<T>: AddsCount,Add,Remove, etc.IList<T>: Supports indexing and positional operations.IQueryable<T>: Represents query expressions (e.g., for databases); execution deferred until enumeration.