C# Dictionary
$count++; if($count == 1) { include "../mobilemenu.php"; } if ($count == 2) { include "../sharemediasubfolder.php"; } ?>
The `Dictionary<TKey, TValue>` class in C# is a part of the `System.Collections.Generic` namespace and represents a collection of key-value pairs that are organized based on the key. It provides fast lookups, additions, and deletions of elements based on the key. Understanding `Dictionary<TKey, TValue>` is essential for efficient data management, especially when quick retrieval of data is required.
Table of Contents
- Introduction to Dictionary<TKey, TValue> - What is Dictionary<TKey, TValue>?
- Declaring and Initializing Dictionary<TKey, TValue> - Declaration Syntax
- Adding and Removing Elements - Adding Elements
- Accessing Elements - By Key
- Iterating Through Dictionary<TKey, TValue> - Using foreach Loop
- Searching and Sorting - Searching for Keys or Values
- Capacity and Performance - Understanding Capacity vs. Count
- Common Methods and Properties - Key Methods
- Best Practices - Choosing the Right Key Type
- Common Mistakes with Dictionary<TKey, TValue> - Duplicate Keys
- Advanced Topics - Custom Comparers
- Real-World Example
- Summary
- Benefits of Using Dictionary<TKey, TValue>
- Initialization Methods
- Collection Initializers
- Adding Range of Elements
- Removing Elements
- Clearing the Dictionary
- Using TryGetValue
- Using ContainsKey and ContainsValue
- Iterating over Keys and Values
- Iterating over Keys and Values Separately
- Sorting Dictionaries
- Managing Capacity
- Performance Considerations
- Important Properties
- Avoiding Duplicate Keys
- Handling KeyNotFoundException
- Using ReadOnly Dictionaries
- Initializing with Capacity
- Using Appropriate Equality Comparers
- Not Checking for Key Existence
- Modifying During Iteration
- Using Mutable Types as Keys
- Thread Safety
- Serialization
- Enumerating in Different Ways
- ConcurrentDictionary and Thread-Safe Operations
- Using Immutable Dictionaries
1. Introduction to Dictionary<TKey, TValue>
What is Dictionary<TKey, TValue>?
`Dictionary<TKey, TValue>` is a generic collection that stores elements as key-value pairs. Each key in the dictionary must be unique, and each key maps to exactly one value. The dictionary uses a hash table for storage, providing near O(1) time complexity for lookups, additions, and deletions.Syntax:
using System.Collections.Generic;
Dictionary<TKey, TValue> dictionary = new Dictionary<TKey, TValue>();
Benefits of Using Dictionary<TKey, TValue>
- Fast Lookups: Provides quick access to elements via keys.- Type Safety: Ensures that keys and values are of specified types.
- Flexibility: Supports a wide range of operations like adding, removing, and searching elements.
- Rich API: Offers numerous methods for managing and manipulating data.
- Integration with LINQ: Seamlessly works with LINQ for advanced querying.
2. Declaring and Initializing Dictionary<TKey, TValue>
2.1 Declaration Syntax
Basic Declaration:using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
Dictionary<int, string> studentGrades = new Dictionary<int, string>();
}
}
Explanation:
- Namespace: Ensure `System.Collections.Generic` is included.
- Type Parameters: Replace `int` and `string` with desired key and value types.
2.2 Initialization Methods
Default Initialization:Dictionary<string, int> wordCounts = new Dictionary<string, int>();
Initialization with Capacity:
Specifying an initial capacity can optimize performance by reducing the number of resizing operations.
Dictionary<string, int> wordCounts = new Dictionary<string, int>(100);
Explanation:- Capacity: The number passed defines the initial size. The dictionary grows as needed beyond this capacity.
2.3 Collection Initializers
Allows initializing a dictionary with key-value pairs at the time of creation.Dictionary<int, string> employeeMap = new Dictionary<int, string>
{
{ 101, "Alice" },
{ 102, "Bob" },
{ 103, "Charlie" }
};
Explanation:
- Readability: Enhances code clarity by initializing with predefined key-value pairs.
3. Adding and Removing Elements
3.1 Adding Elements
Using Add Method:Adds a key-value pair to the dictionary.
employeeMap.Add(104, "David");
Using Indexer:
Adds or updates a key-value pair using the indexer.
employeeMap[105] = "Eve"; // Adds if key 105 doesn't exist, updates if it does
Explanation:
- Add: Throws an exception if the key already exists.
- Indexer: Adds or updates without throwing an exception.
3.2 Adding Range of Elements
Although `Dictionary<TKey, TValue>` doesn't have a built-in `AddRange` method, you can add multiple elements using `foreach`.var newEmployees = new Dictionary<int, string>
{
{ 106, "Frank" },
{ 107, "Grace" }
};
foreach(var kvp in newEmployees)
{
employeeMap.Add(kvp.Key, kvp.Value);
}
Explanation:
- Bulk Addition: Iterates over another dictionary to add multiple elements.
3.3 Removing Elements
Using Remove Method:Removes the element with the specified key.
employeeMap.Remove(102); // Removes the key-value pair with key 102
Using Clear Method:
Removes all elements from the dictionary.
employeeMap.Clear();
Explanation:
- Remove: Returns `true` if the element is successfully found and removed; otherwise, `false`.
- Clear: Empties the entire dictionary.
3.4 Clearing the Dictionary
Using Clear Method:employeeMap.Clear();
Explanation:- Clear: Removes all key-value pairs but retains the existing capacity for future additions.
4. Accessing Elements
4.1 By Key
Accessing a value by its key using the indexer.string employeeName = employeeMap[101]; // Retrieves "Alice"
Explanation:
- Direct Access: Fast retrieval if the key exists.
- Exception Handling: Throws `KeyNotFoundException` if the key doesn't exist.
4.2 Using TryGetValue
Safely attempts to get the value associated with the specified key without throwing an exception.if(employeeMap.TryGetValue(102, out string name))
{
Console.WriteLine($"Employee 102: {name}");
}
else
{
Console.WriteLine("Employee 102 not found.");
}
Explanation:- Safe Retrieval: Prevents exceptions by checking if the key exists before accessing.
4.3 Using ContainsKey and ContainsValue
ContainsKey Method:Checks if a key exists in the dictionary.
bool hasKey = employeeMap.ContainsKey(103); // true or false
ContainsValue Method:
Checks if a value exists in the dictionary.
bool hasValue = employeeMap.ContainsValue("Eve"); // true or false
Explanation:
- ContainsKey: Efficient for verifying the presence of a key.
- ContainsValue: May be slower as it requires iterating through all values.
4.4 Iterating over Keys and Values
Accessing Keys:foreach(int key in employeeMap.Keys)
{
Console.WriteLine(key);
}
Accessing Values:
foreach(string value in employeeMap.Values)
{
Console.WriteLine(value);
}
Explanation:
- Keys and Values Properties: Allow separate iteration over keys or values.
5. Iterating Through Dictionary<TKey, TValue>
5.1 Using foreach Loop
Iterate over each key-value pair using `KeyValuePair<TKey, TValue>`.foreach(KeyValuePair<int, string> kvp in employeeMap)
{
Console.WriteLine($"ID: {kvp.Key}, Name: {kvp.Value}");
}
Explanation:
- KeyValuePair: Provides access to both key and value in each iteration.
5.2 Iterating over Keys and Values Separately
Iterate Over Keys:foreach(int key in employeeMap.Keys)
{
Console.WriteLine($"Key: {key}");
}
Iterate Over Values:
foreach(string name in employeeMap.Values)
{
Console.WriteLine($"Name: {name}");
}
Explanation:
- Separate Iteration: Useful when only keys or values are needed.
6. Searching and Sorting
6.1 Searching for Keys or Values
Finding a Key:bool exists = employeeMap.ContainsKey(104); // true or false
Finding a Value:
bool exists = employeeMap.ContainsValue("Bob"); // true or false
Explanation:
- ContainsKey and ContainsValue: Efficient methods for checking existence.
6.2 Sorting Dictionaries
`Dictionary<TKey, TValue>` does not maintain order. To sort, you need to create a sorted representation.Example: Sorting by Key
var sortedByKey = employeeMap.OrderBy(kvp => kvp.Key);
Console.WriteLine("Sorted by Key:");
foreach(var kvp in sortedByKey)
{
Console.WriteLine($"ID: {kvp.Key}, Name: {kvp.Value}");
}
Example: Sorting by Value
var sortedByValue = employeeMap.OrderBy(kvp => kvp.Value);
Console.WriteLine("Sorted by Value:");
foreach(var kvp in sortedByValue)
{
Console.WriteLine($"ID: {kvp.Key}, Name: {kvp.Value}");
}
Explanation:- LINQ OrderBy: Creates a new ordered sequence based on the specified key or value.
- Immutable: Does not change the original dictionary.
7. Capacity and Performance
7.1 Understanding Capacity vs. Count
- Count: The number of key-value pairs actually in the dictionary.- Capacity: The number of elements the dictionary can hold before resizing is required.
Example:
Dictionary<int, string> dict = new Dictionary<int, string>();
Console.WriteLine($"Initial Capacity: {dict.Count}"); // Output: 0
dict.Add(1, "One");
Console.WriteLine($"Count after adding one element: {dict.Count}"); // Output: 1
dict.Add(2, "Two");
Console.WriteLine($"Count after adding two elements: {dict.Count}"); // Output: 2
Explanation:
- Count Property: Reflects the current number of elements.
- Capacity Management: Internal resizing handled automatically.
7.2 Managing Capacity
Using EnsureCapacity Method:Ensures that the dictionary can hold a specified number of elements without resizing.
employeeMap.EnsureCapacity(200);
Using TrimExcess Method:
Reduces the capacity to match the current count, minimizing memory usage.
employeeMap.TrimExcess();
Explanation:- EnsureCapacity: Prevents frequent resizing by allocating sufficient space upfront.
- TrimExcess: Frees unused memory after bulk operations.
7.3 Performance Considerations
- Pre-Allocating Capacity: If the number of elements is known, initializing with appropriate capacity can enhance performance.- Avoiding Excessive Capacity: Over-allocating can lead to unnecessary memory usage.
- Hash Function Efficiency: Choosing appropriate key types with good hash functions ensures efficient operations.
8. Common Methods and Properties
8.1 Key Methods
- Add(TKey key, TValue value): Adds a key-value pair to the dictionary.- TryAdd(TKey key, TValue value): Attempts to add a key-value pair; returns `false` if the key already exists.
- Remove(TKey key): Removes the element with the specified key. - Clear(): Removes all elements from the dictionary.
- ContainsKey(TKey key): Checks if the dictionary contains the specified key.
- ContainsValue(TValue value): Checks if the dictionary contains the specified value.
- TryGetValue(TKey key, out TValue value): Attempts to get the value associated with the specified key.
- AddRange(IEnumerable<KeyValuePair<TKey, TValue>> collection): Not available by default, but can be implemented using extension methods or loops.
- GetEnumerator(): Returns an enumerator for iterating through the dictionary.
8.2 Important Properties
- Count: Gets the number of key-value pairs in the dictionary.- Keys: Gets a collection containing all the keys in the dictionary.
- Values: Gets a collection containing all the values in the dictionary.
- Comparer: Gets the `IEqualityComparer<TKey>` that is used to determine equality of keys.
- Capacity: Although `Dictionary<TKey, TValue>` does not expose a `Capacity` property directly, it can be managed via constructors and `EnsureCapacity` method.
9. Best Practices
9.1 Choosing the Right Key Type
- Uniqueness: Keys must be unique; choose types that naturally provide unique identifiers (e.g., IDs, GUIDs).- Immutability: Use immutable types as keys to ensure consistency in hashing and equality checks.
- Hash Function Quality: Select key types with good hash functions to minimize collisions and optimize performance.
Example: Using GUID as Key
Dictionary<Guid, string> guidMap = new Dictionary<Guid, string>();
Guid key = Guid.NewGuid();
guidMap.Add(key, "UniqueValue");
9.2 Avoiding Duplicate Keys
- Use Add Method Carefully: Since `Add` throws an exception if the key exists, consider using `TryAdd` or check with `ContainsKey` before adding.- Handling Exceptions: Implement proper exception handling when adding elements.
Example: Using TryAdd
bool added = employeeMap.TryAdd(108, "Hannah");
if(!added)
{
Console.WriteLine("Key already exists.");
}
9.3 Handling KeyNotFoundException
- Use TryGetValue: Safely retrieve values without risking exceptions.- Check ContainsKey: Verify key existence before accessing.
Example: Using TryGetValue
if(employeeMap.TryGetValue(109, out string name))
{
Console.WriteLine($"Employee 109: {name}");
}
else
{
Console.WriteLine("Employee 109 not found.");
}
9.4 Using ReadOnly Dictionaries
To expose dictionaries without allowing modification, use read-only wrappers.using System.Collections.ObjectModel;
ReadOnlyDictionary<int, string> readOnlyDict = new ReadOnlyDictionary<int, string>(employeeMap);
Explanation:- Encapsulation: Prevents external code from altering the dictionary.
- Safety: Ensures data integrity.
9.5 Initializing with Capacity
If the number of elements is known upfront, initialize the dictionary with an appropriate capacity to optimize performance.Dictionary<int, string> largeDict = new Dictionary<int, string>(1000);
Explanation:
- Performance: Reduces the need for resizing as elements are added.
9.6 Using Appropriate Equality Comparers
Customize how keys are compared by providing an `IEqualityComparer<TKey>`.public class CaseInsensitiveComparer : IEqualityComparer
{
public bool Equals(string x, string y)
{
return string.Equals(x, y, StringComparison.OrdinalIgnoreCase);
}
public int GetHashCode(string obj)
{
return obj.ToLower().GetHashCode();
}
}
// Usage
Dictionary<string, int> caseInsensitiveDict = new Dictionary<string, int>(new CaseInsensitiveComparer());
caseInsensitiveDict.Add("Key", 1);
bool exists = caseInsensitiveDict.ContainsKey("key"); // true
Explanation:- Customization: Allows defining how keys are compared and hashed.
10. Common Mistakes with Dictionary<TKey, TValue>
10.1 Duplicate Keys
Attempting to add a key that already exists using the `Add` method throws an exception.Example:
employeeMap.Add(101, "Alice"); // Throws ArgumentException if key 101 exists
Solution: Use `TryAdd` or check with `ContainsKey` before adding.10.2 Not Checking for Key Existence
Accessing a key that doesn't exist using the indexer throws a `KeyNotFoundException`.Example:
string name = employeeMap[110]; // Throws exception if key 110 doesn't exist
Solution: Use `TryGetValue` or `ContainsKey` to safely access elements.10.3 Modifying the Dictionary During Iteration
Altering the dictionary (adding or removing elements) while iterating can cause runtime exceptions.Example:
foreach(var kvp in employeeMap)
{
if(kvp.Key == 101)
{
employeeMap.Remove(kvp.Key); // InvalidOperationException
}
}
Solution: Iterate over a copy of the keys or use other safe iteration methods.Corrected Example:
foreach(var key in employeeMap.Keys.ToList())
{
if(key == 101)
{
employeeMap.Remove(key);
}
}
10.4 Using Mutable Types as Keys
Using mutable types as keys can lead to unpredictable behavior because changes can affect the hash code and equality.Example:
public class Person
{
public string Name { get; set; }
// Mutable property affecting hash code
}
Dictionary<Person, int> personDict = new Dictionary<Person, int>();
Person p = new Person { Name = "Alice" };
personDict.Add(p, 1);
// Modifying the key after adding
p.Name = "Alicia"; // Alters the hash code
Solution: Use immutable types as keys or ensure that key properties affecting equality are not modified after adding.11. Advanced Topics
11.1 Custom Comparers
Implement custom logic for key comparison by creating a class that implements `IEqualityComparer<TKey>`.Example: Custom String Comparer (Case-Insensitive)
public class CaseInsensitiveStringComparer : IEqualityComparer
{
public bool Equals(string x, string y)
{
return string.Equals(x, y, StringComparison.OrdinalIgnoreCase);
}
public int GetHashCode(string obj)
{
return obj.ToLower().GetHashCode();
}
}
// Usage
Dictionary<string, int> ciDict = new Dictionary<string, int>(new CaseInsensitiveStringComparer());
ciDict.Add("Key", 1);
bool exists = ciDict.ContainsKey("key"); // true
Explanation:
- Customization: Defines how keys are compared and hashed, enabling case-insensitive operations.
11.2 Thread Safety
`Dictionary<TKey, TValue>` is not thread-safe. To use it in multi-threaded environments, implement synchronization or use concurrent collections.Example: Using Lock for Thread Safety
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
class Program
{
static Dictionary<int, string> employeeMap = new Dictionary<int, string>();
static object lockObj = new object();
static void Main()
{
Parallel.For(0, 1000, i =>
{
lock(lockObj)
{
employeeMap[i] = $"Employee{i}";
}
});
Console.WriteLine($"Total Employees: {employeeMap.Count}"); // Output: 1000
}
}
Explanation:
- Locking Mechanism: Ensures that only one thread modifies the dictionary at a time, preventing data races.
11.3 Serialization
`Dictionary<TKey, TValue>` can be serialized using various serializers like JSON, XML, or binary serializers.Example: Serializing to JSON
using System;
using System.Collections.Generic;
using System.Text.Json;
class Program
{
static void Main()
{
Dictionary<int, string> employeeMap = new Dictionary<int, string>
{
{ 101, "Alice" },
{ 102, "Bob" }
};
string json = JsonSerializer.Serialize(employeeMap);
Console.WriteLine(json); // Output: {"101":"Alice","102":"Bob"}
}
}
Explanation:
- Serialization: Converts the dictionary to a JSON string for storage or transmission.
11.4 Enumerating in Different Ways
Enumerate Keys:foreach(int key in employeeMap.Keys)
{
Console.WriteLine(key);
}
Enumerate Values:
foreach(string value in employeeMap.Values)
{
Console.WriteLine(value);
}
Enumerate KeyValuePairs:
foreach(var kvp in employeeMap)
{
Console.WriteLine($"Key: {kvp.Key}, Value: {kvp.Value}");
}
Explanation:
- Flexible Enumeration: Allows different ways to iterate based on requirements.
11.5 ConcurrentDictionary and Thread-Safe Operations
For multi-threaded scenarios, use `ConcurrentDictionary<TKey, TValue>` which provides thread-safe operations without the need for explicit locking.Example: Using ConcurrentDictionary
using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;
class Program
{
static ConcurrentDictionary<int, string> concurrentDict = new ConcurrentDictionary<int, string>();
static void Main()
{
Parallel.For(0, 1000, i =>
{
concurrentDict.TryAdd(i, $"Employee{i}");
});
Console.WriteLine($"Total Employees: {concurrentDict.Count}"); // Output: 1000
}
}
Explanation:
- Thread Safety: Allows safe concurrent additions and updates without manual synchronization.
- Performance: Optimized for high-concurrency scenarios.
11.6 Using Immutable Dictionaries
Immutable dictionaries cannot be modified after creation, ensuring thread safety and consistency.Example: Using ImmutableDictionary
using System;
using System.Collections.Immutable;
class Program
{
static void Main()
{
var builder = ImmutableDictionary.CreateBuilder<int, string>();
builder.Add(101, "Alice");
builder.Add(102, "Bob");
ImmutableDictionary<int, string> immutableDict = builder.ToImmutable();
Console.WriteLine("Immutable Dictionary:");
foreach(var kvp in immutableDict)
{
Console.WriteLine($"ID: {kvp.Key}, Name: {kvp.Value}");
}
}
}
Explanation:
- Immutability: Guarantees that the dictionary cannot change after creation, enhancing safety in multi-threaded environments.
12. Real-World Example
Example: Employee Directory Management Using Dictionary<TKey, TValue>
This example demonstrates managing an employee directory where each employee has a unique ID and associated information. The dictionary allows quick retrieval, addition, and removal of employee records based on their IDs.Code Example:
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
EmployeeDirectory directory = new EmployeeDirectory();
// Adding employees
directory.AddEmployee(new Employee { Id = 101, Name = "Alice", Position = "Developer" });
directory.AddEmployee(new Employee { Id = 102, Name = "Bob", Position = "Designer" });
directory.AddEmployee(new Employee { Id = 103, Name = "Charlie", Position = "Manager" });
// Display all employees
Console.WriteLine("All Employees:");
directory.DisplayAllEmployees();
// Search for an employee
Console.WriteLine("\nSearching for Employee with ID 102:");
var employee = directory.GetEmployeeById(102);
if(employee != null)
{
Console.WriteLine(employee);
}
else
{
Console.WriteLine("Employee not found.");
}
// Update an employee's position
Console.WriteLine("\nUpdating Employee with ID 103:");
directory.UpdateEmployeePosition(103, "Senior Manager");
directory.DisplayAllEmployees();
// Remove an employee
Console.WriteLine("\nRemoving Employee with ID 101:");
directory.RemoveEmployee(101);
directory.DisplayAllEmployees();
// Attempt to add a duplicate employee
Console.WriteLine("\nAttempting to Add Employee with Duplicate ID 102:");
directory.AddEmployee(new Employee { Id = 102, Name = "David", Position = "Intern" });
}
}
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public string Position { get; set; }
public override string ToString()
{
return $"ID: {Id}, Name: {Name}, Position: {Position}";
}
}
public class EmployeeDirectory
{
private Dictionary<int, Employee> employees = new Dictionary<int, Employee>();
public void AddEmployee(Employee employee)
{
if(employees.ContainsKey(employee.Id))
{
Console.WriteLine($"Error: Employee with ID {employee.Id} already exists.");
return;
}
employees.Add(employee.Id, employee);
Console.WriteLine($"Added Employee: {employee.Name}");
}
public Employee GetEmployeeById(int id)
{
if(employees.TryGetValue(id, out Employee employee))
{
return employee;
}
return null;
}
public void UpdateEmployeePosition(int id, string newPosition)
{
if(employees.TryGetValue(id, out Employee employee))
{
employee.Position = newPosition;
Console.WriteLine($"Updated Position for Employee ID {id} to {newPosition}.");
}
else
{
Console.WriteLine($"Error: Employee with ID {id} not found.");
}
}
public void RemoveEmployee(int id)
{
if(employees.Remove(id))
{
Console.WriteLine($"Removed Employee with ID {id}.");
}
else
{
Console.WriteLine($"Error: Employee with ID {id} not found.");
}
}
public void DisplayAllEmployees()
{
foreach(var kvp in employees)
{
Console.WriteLine(kvp.Value);
}
}
}
Sample Output:
Added Employee: Alice
Added Employee: Bob
Added Employee: Charlie
All Employees:
ID: 101, Name: Alice, Position: Developer
ID: 102, Name: Bob, Position: Designer
ID: 103, Name: Charlie, Position: Manager
Searching for Employee with ID 102:
ID: 102, Name: Bob, Position: Designer
Updating Employee with ID 103:
Updated Position for Employee ID 103 to Senior Manager.
All Employees:
ID: 101, Name: Alice, Position: Developer
ID: 102, Name: Bob, Position: Designer
ID: 103, Name: Charlie, Position: Senior Manager
Removing Employee with ID 101:
Removed Employee with ID 101.
All Employees:
ID: 102, Name: Bob, Position: Designer
ID: 103, Name: Charlie, Position: Senior Manager
Attempting to Add Employee with Duplicate ID 102:
Error: Employee with ID 102 already exists.
Explanation:
- Employee Class: Represents an employee with properties like `Id`, `Name`, and `Position`.
- EmployeeDirectory Class: Manages a `Dictionary<int, Employee>` to handle employee records.
- AddEmployee: Adds a new employee if the ID doesn't already exist.
- GetEmployeeById: Retrieves an employee by their ID using `TryGetValue`.
- UpdateEmployeePosition: Updates the position of an existing employee.
- RemoveEmployee: Removes an employee based on their ID.
- DisplayAllEmployees: Iterates over the dictionary to display all employees.
- Main Method: Demonstrates adding, searching, updating, and removing employees, as well as handling duplicate keys.
13. Summary
The `Dictionary<TKey, TValue>` class in C# is a versatile and efficient collection for storing and managing key-value pairs. It offers fast lookups, additions, and deletions, making it ideal for scenarios where quick access to data based on unique keys is essential.Key Takeaways:
- Fast Access: Provides near O(1) time complexity for most operations, ensuring quick data retrieval.
- Type Safety: Generic implementation ensures that only specified types are used for keys and values, reducing runtime errors.
- Rich API: Offers a wide range of methods and properties for managing data effectively.
- Flexible Initialization: Supports various initialization methods, including specifying capacity and using collection initializers.
- Customization: Allows the use of custom equality comparers to define how keys are compared and hashed.
- Thread Safety: Not inherently thread-safe; use synchronization mechanisms or concurrent collections like `ConcurrentDictionary<TKey, TValue>` for multi-threaded scenarios.
- Best Practices:
- Choose immutable and unique key types.
- Avoid duplicate keys to prevent exceptions.
- Use `TryGetValue` to safely access elements.
- Initialize with appropriate capacity when the size is known.
- Leverage LINQ for advanced querying and sorting.
- Common Mistakes:
- Adding duplicate keys without handling exceptions.
- Not checking for key existence before accessing.
- Modifying the dictionary during iteration.
- Using mutable types as keys, leading to unpredictable behavior.
- Advanced Usage: Implement custom comparers, handle serialization, and utilize thread-safe or immutable variants for specialized needs.
- Real-World Applications: Ideal for scenarios like employee directories, caching systems, configuration settings, and any case requiring fast, key-based data access.
By mastering `Dictionary<TKey, TValue>`, you enhance your ability to manage and manipulate collections of data efficiently, leading to more robust and maintainable C# applications.