Collections in .NET
The .NET Framework provides a rich set of types for working with collections of objects. These types are found in the System.Collections
and System.Collections.Generic
namespaces. Collections allow you to store, retrieve, and manipulate groups of objects efficiently.
Key Concepts
Understanding the following concepts is crucial for effective use of .NET collections:
- Interfaces: Collections are often defined by interfaces (e.g.,
IEnumerable<T>
,ICollection<T>
,IList<T>
,IDictionary<TKey, TValue>
), which provide a contract for collection behavior. - Generic Collections: Introduced with .NET 2.0, generic collections (in
System.Collections.Generic
) provide type safety and improved performance by allowing you to specify the type of elements the collection can hold (e.g.,List<string>
). - Non-Generic Collections: Older collections (in
System.Collections
) store elements asobject
and require casting, which can lead to runtime errors. Use generic collections whenever possible. - Abstract Base Classes: Classes like
Collection<T>
andReadOnlyCollection<T>
provide abstract implementations that simplify the creation of custom collection types.
Common Collection Types
Here are some of the most commonly used collection types:
Generic Collections (System.Collections.Generic
)
Type | Description | Common Use Cases |
---|---|---|
List<T> |
Represents a list of objects that can be accessed by index. It is dynamically sized. | Storing sequences of items, when the order matters, and frequent addition/removal is needed. |
Dictionary<TKey, TValue> |
Represents a collection of key/value pairs. Keys must be unique. | Storing data that needs to be quickly accessed by a unique identifier (key). |
HashSet<T> |
Represents a set of unique elements. Order is not guaranteed. | Checking for the presence of an element efficiently, removing duplicates. |
Queue<T> |
Represents a first-in, first-out (FIFO) collection of objects. | Processing items in the order they were received (e.g., task queues). |
Stack<T> |
Represents a last-in, first-out (LIFO) collection of objects. | Implementing undo/redo functionality, parsing expressions. |
LinkedList<T> |
Represents a doubly linked list. | Scenarios requiring frequent insertions or deletions in the middle of a sequence. |
Non-Generic Collections (System.Collections
)
While these are still supported, it is highly recommended to use their generic counterparts for type safety and performance benefits.
Type | Description |
---|---|
ArrayList |
A non-generic list that can hold objects of any type. Requires casting. |
Hashtable |
A non-generic dictionary that stores key/value pairs. Keys and values are of type object . |
Queue |
A non-generic FIFO collection. |
Stack |
A non-generic LIFO collection. |
Example: Using List<T>
Here's a simple example demonstrating how to use a List<string>
:
using System;
using System.Collections.Generic;
public class Example
{
public static void Main(string[] args)
{
// Create a list of strings
List<string> fruits = new List<string>();
// Add elements to the list
fruits.Add("Apple");
fruits.Add("Banana");
fruits.Add("Cherry");
// Access elements by index
Console.WriteLine($"First fruit: {fruits[0]}"); // Output: First fruit: Apple
// Iterate through the list
Console.WriteLine("All fruits:");
foreach (string fruit in fruits)
{
Console.WriteLine($"- {fruit}");
}
// Check if an item exists
if (fruits.Contains("Banana"))
{
Console.WriteLine("Banana is in the list.");
}
// Remove an item
fruits.Remove("Banana");
Console.WriteLine($"List after removing Banana: {string.Join(", ", fruits)}");
}
}
Example: Using Dictionary<TKey, TValue>
This example shows how to use a Dictionary<int, string>
:
using System;
using System.Collections.Generic;
public class Example
{
public static void Main(string[] args)
{
// Create a dictionary mapping employee IDs to names
Dictionary<int, string> employees = new Dictionary<int, string>();
// Add key-value pairs
employees.Add(101, "Alice");
employees.Add(102, "Bob");
employees.Add(103, "Charlie");
// Access a value by key
Console.WriteLine($"Employee with ID 102: {employees[102]}"); // Output: Employee with ID 102: Bob
// Check if a key exists
if (employees.ContainsKey(105))
{
Console.WriteLine("Employee 105 found.");
}
else
{
Console.WriteLine("Employee 105 not found."); // Output: Employee 105 not found.
}
// Iterate through the dictionary
Console.WriteLine("Employee List:");
foreach (KeyValuePair<int, string> employee in employees)
{
Console.WriteLine($"ID: {employee.Key}, Name: {employee.Value}");
}
}
}
LinkedList<T>
can be more efficient than List<T>
due to its node-based structure. However, accessing elements by index is much slower in a LinkedList<T>
.
Exploring the various collection types and their associated interfaces will empower you to choose the most appropriate data structure for your specific programming needs, leading to more efficient and maintainable code.