Non-Generic Collections in C# – Examples
Non-generic collections store multiple elements without requiring a specific data type. They can hold different data types in the same collection.
Namespace: System.Collections
1. ArrayList – Dynamic Array
Stores multiple elements, allows duplicates, and supports different data types.
using System.Collections;
ArrayList items = new ArrayList();
items.Add(10);
items.Add("John");
items.Add(25.5);
items.Add(true);
items.Remove("John");
foreach (object item in items)
{
Console.WriteLine(item);
}
// Output:
// 10
// 25.5
// True
Key Points: Dynamic size, allows duplicates, supports mixed data types, requires casting when retrieving typed values.
2. Hashtable – Key-Value Pairs
Stores data as key-value pairs. Keys must be unique.
using System.Collections;
Hashtable employees = new Hashtable();
employees.Add(101, "John");
employees.Add(102, "David");
employees.Add(103, "Peter");
Console.WriteLine(employees[102]);
foreach (DictionaryEntry emp in employees)
{
Console.WriteLine($"{emp.Key} - {emp.Value}");
}
// Output: David
// Remaining entries: 101-John, 102-David, 103-Peter
// Enumeration order is not guaranteed
Key Points: Unique keys, duplicate values allowed, fast key-based lookup, no guaranteed ordering.
3. Stack – LIFO
Stack follows Last In, First Out (LIFO). The last inserted element is removed first.
using System.Collections;
Stack stack = new Stack();
stack.Push(10);
stack.Push("John");
stack.Push(30);
Console.WriteLine(stack.Pop()); // 30
Console.WriteLine(stack.Peek()); // John
Console.WriteLine(stack.Count); // 2
Key Points: Push() adds, Pop() removes, Peek() reads the top element without removing it.
4. Queue – FIFO
Queue follows First In, First Out (FIFO). The first inserted element is removed first.
using System.Collections;
Queue queue = new Queue();
queue.Enqueue("John");
queue.Enqueue(100);
queue.Enqueue("David");
Console.WriteLine(queue.Dequeue()); // John
Console.WriteLine(queue.Peek()); // 100
Console.WriteLine(queue.Count); // 2
Key Points: Enqueue() adds, Dequeue() removes, Peek() reads the first element.
5. SortedList – Sorted Key-Value Pairs
Stores key-value pairs automatically sorted by key.
using System.Collections;
SortedList students = new SortedList();
students.Add(3, "Peter");
students.Add(1, "John");
students.Add(2, "David");
foreach (DictionaryEntry student in students)
{
Console.WriteLine($"{student.Key} - {student.Value}");
}
// Output:
// 1 - John
// 2 - David
// 3 - Peter
Key Points: Unique keys, automatically sorted, supports index-based access through GetByIndex() and GetKey().
6. BitArray – Collection of Boolean Values
Stores a sequence of bits represented as true or false.
using System.Collections;
BitArray bits = new BitArray(4);
bits[0] = true;
bits[1] = false;
bits[2] = true;
bits[3] = true;
foreach (bool bit in bits)
{
Console.WriteLine(bit);
}
// Output:
// True
// False
// True
// True
Key Points: Memory-efficient bit storage, supports bitwise operations such as And(), Or(), Xor() and Not().
Non-Generic Collections – Quick Comparison
|
Collection |
Duplicates |
Ordering |
Best Use |
|---|---|---|---|
|
|
Yes |
Insertion order |
Dynamic mixed-type lists |
|
|
Values only |
Not guaranteed |
Key-value lookup |
|
|
Yes |
LIFO |
Undo operations |
|
|
Yes |
FIFO |
Task processing |
|
|
Values only |
Sorted keys |
Sorted key-value pairs |
|
|
Yes |
Index order |
Bit manipulation |
Generic vs Non-Generic Collections
|
Feature |
Generic |
Non-Generic |
|---|---|---|
|
Namespace |
|
|
|
Type safety |
Compile-time |
Runtime |
|
Data types |
Specified types |
Mixed types |
|
Boxing/unboxing |
Generally avoided |
Required for value types stored as objects |
|
Performance |
Generally better |
May have boxing/casting overhead |
|
Examples |
|
|
|
Recommendation |
Preferred for new code |
Mainly legacy compatibility |
Important Interview Questions
1. What is a non-generic collection? A collection that stores elements as object without specifying a compile-time element type. It can store different data types.
2. ArrayList vs List<T>? ArrayList stores elements as objects and is not type-safe. List<T> provides compile-time type safety and avoids boxing for value types.
3. Hashtable vs Dictionary<TKey, TValue>? Hashtable stores keys and values as objects. Dictionary<TKey,TValue> is strongly typed and generally preferred in modern C#.
4. What is boxing and unboxing? Boxing converts a value type into an object. Unboxing extracts the value type from the boxed object.
ArrayList list = new ArrayList();
list.Add(100); // Boxing
int number = (int)list[0]; // Unboxing
5. Are non-generic collections thread-safe? Most are not inherently safe for concurrent modifications. Synchronization is required when multiple threads modify the same collection.
6. Which is recommended in modern C#? Generic collections such as List<T>, Dictionary<TKey,TValue>, Stack<T> and Queue<T> are generally recommended because they provide type safety and better performance characteristics.
Interview takeaway: Use generic collections for modern .NET development. Understand non-generic collections primarily for legacy application maintenance and interview comparisons.