Arrays and Collections in .NET
This document provides an in-depth overview of arrays and collections in the .NET framework. Understanding how to store and manage data efficiently is crucial for building robust and performant applications.
Arrays
Arrays are fixed-size data structures that store elements of the same type. They are zero-indexed, meaning the first element is at index 0.
Declaring and Initializing Arrays
// Declaring an array of integers
int[] numbers;
// Declaring and initializing an array with values
string[] names = {"Alice", "Bob", "Charlie"};
// Declaring and initializing an array with a specific size
char[] letters = new char[5];
Accessing Array Elements
string firstName = names[0]; // "Alice"
letters[2] = 'X';
Array Properties and Methods
The System.Array class provides useful properties and methods:
Length: Gets the total number of elements in the array.Rank: Gets the number of dimensions (rank) of the array.Sort(): Sorts the elements in ascending order.Reverse(): Reverses the order of elements.
int count = names.Length; // 3
Array.Sort(names);
Array.Reverse(letters);
Collections
Collections are more flexible than arrays and provide various ways to store and manipulate groups of objects. They are part of the System.Collections and System.Collections.Generic namespaces.
Common Non-Generic Collections (System.Collections)
These collections store objects of type object, requiring casting and potentially leading to runtime errors if the type is incorrect. They are generally less preferred in modern .NET development.
| Collection Type | Description | Use Cases |
|---|---|---|
ArrayList |
A dynamic array that can grow or shrink. | When the type of elements is unknown at compile time and flexibility is paramount (though generics are preferred). |
Hashtable |
A collection of key-value pairs. | Storing data where fast lookup by a unique key is needed. |
Queue |
First-In, First-Out (FIFO) collection. | Implementing waiting lists or task queues. |
Stack |
Last-In, First-Out (LIFO) collection. | Managing call stacks or undo/redo operations. |
System.Collections.Generic namespace whenever possible.
Generic Collections (System.Collections.Generic)
Generic collections provide compile-time type safety and improved performance by avoiding boxing and unboxing operations.
| Collection Type | Description | Use Cases |
|---|---|---|
List<T> |
A strongly-typed dynamic array. | The most common and versatile collection for ordered lists of a specific type. |
Dictionary<TKey, TValue> |
A strongly-typed collection of key-value pairs. | Efficient lookup of values using a specific key type. |
HashSet<T> |
A collection of unique elements, optimized for fast lookups. | Storing unique items where order doesn't matter and checking for existence is frequent. |
Queue<T> |
A strongly-typed FIFO collection. | Implementing type-safe waiting lists. |
Stack<T> |
A strongly-typed LIFO collection. | Implementing type-safe stacks. |
List<T> Example
// List of strings
List<string> fruits = new List<string>();
fruits.Add("Apple");
fruits.Add("Banana");
fruits.Add("Orange");
// Accessing elements
string firstFruit = fruits[0]; // "Apple"
// Adding and removing
fruits.Insert(1, "Grape"); // ["Apple", "Grape", "Banana", "Orange"]
fruits.Remove("Banana"); // ["Apple", "Grape", "Orange"]
// Iterating
foreach (string fruit in fruits)
{
Console.WriteLine(fruit);
}
Dictionary<TKey, TValue> Example
// Dictionary mapping product IDs to names
Dictionary<int, string> products = new Dictionary<int, string>();
products.Add(101, "Laptop");
products.Add(102, "Keyboard");
// Adding using indexer (if key doesn't exist)
products[103] = "Mouse";
// Accessing values
string productName = products[101]; // "Laptop"
// Checking for keys
if (products.ContainsKey(102))
{
Console.WriteLine("Keyboard is in the dictionary.");
}
// Iterating through key-value pairs
foreach (KeyValuePair<int, string> kvp in products)
{
Console.WriteLine($"ID: {kvp.Key}, Name: {kvp.Value}");
}
Where(), Select(), OrderBy()) for powerful querying and manipulation of collections. See the LINQ section for more details.
Choosing the Right Collection
The choice of array or collection depends on your specific needs:
- Use arrays for fixed-size collections of a single type when performance is critical and you know the size beforehand.
- Use
List<T>for dynamically sized lists of a specific type. - Use
Dictionary<TKey, TValue>for fast lookups by key. - Use
HashSet<T>when you need to store unique items and perform fast membership checks. - Use
Queue<T>orStack<T>for FIFO or LIFO scenarios, respectively.
Always prioritize generic collections for type safety and better performance.