Enhance Your Collections: Top Extension Methods for C# Dictionaries

C# dictionaries are one of the most powerful collection types, providing fast key-value pair lookups. However, their built-in methods sometimes fall short when dealing with real-world scenarios. To maximize efficiency and readability, extension methods allow developers to enhance dictionary functionality without modifying its core implementation.

In this article, we’ll explore some of the most useful extension methods to improve your experience with Dictionary<TKey, TValue>. These methods will help you write cleaner, more efficient, and more expressive code while working with dictionaries in C#.


Why Use Extension Methods for Dictionaries?

1. Improved Readability

Adding custom methods simplifies dictionary operations, making the code more intuitive.

2. Code Reusability

Encapsulating logic in extension methods promotes reusability across different projects.

3. Enhanced Maintainability

Having dedicated methods reduces duplicate logic, making it easier to update and maintain the code.


1. Safe Retrieval with Default Values

A common issue when accessing dictionary values is handling missing keys. Instead of checking with ContainsKey, we can use an extension method to return a default value.

public static class DictionaryExtensions
{
    public static TValue GetValueOrDefault<TKey, TValue>(
        this Dictionary<TKey, TValue> dictionary,
        TKey key,
        TValue defaultValue = default)
    {
        return dictionary.TryGetValue(key, out var value) ? value : defaultValue;
    }
}

Usage:

var settings = new Dictionary<string, string>
{
    {"Theme", "Dark"},
    {"FontSize", "14"}
};

string language = settings.GetValueOrDefault("Language", "English");
Console.WriteLine(language); // Output: English

2. Adding or Updating Entries

Instead of checking for a key’s existence and then updating or inserting, we can create a concise helper method:

public static void AddOrUpdate<TKey, TValue>(
    this Dictionary<TKey, TValue> dictionary,
    TKey key,
    TValue value)
{
    dictionary[key] = value;
}

Usage:

var cache = new Dictionary<int, string>();
cache.AddOrUpdate(1, "Item1");
cache.AddOrUpdate(1, "UpdatedItem");
Console.WriteLine(cache[1]); // Output: UpdatedItem

3. Removing by Predicate

Sometimes, you need to remove dictionary entries based on a condition. We can create an extension method that removes items based on a predicate:

public static void RemoveWhere<TKey, TValue>(
    this Dictionary<TKey, TValue> dictionary,
    Func<TKey, TValue, bool> predicate)
{
    var keysToRemove = dictionary.Where(kvp => predicate(kvp.Key, kvp.Value))
                                 .Select(kvp => kvp.Key)
                                 .ToList();
    
    foreach (var key in keysToRemove)
    {
        dictionary.Remove(key);
    }
}

Usage:

var userRoles = new Dictionary<int, string>
{
    {1, "Admin"},
    {2, "User"},
    {3, "Guest"}
};

userRoles.RemoveWhere((key, value) => value == "Guest");
Console.WriteLine(userRoles.Count); // Output: 2

4. Merging Dictionaries

If you often need to combine dictionaries, this method helps merge two dictionaries while handling conflicts.

public static void Merge<TKey, TValue>(
    this Dictionary<TKey, TValue> target,
    Dictionary<TKey, TValue> source,
    Func<TValue, TValue, TValue> conflictResolver)
{
    foreach (var kvp in source)
    {
        if (target.ContainsKey(kvp.Key))
        {
            target[kvp.Key] = conflictResolver(target[kvp.Key], kvp.Value);
        }
        else
        {
            target.Add(kvp.Key, kvp.Value);
        }
    }
}

Usage:

var dict1 = new Dictionary<string, int>
{
    {"A", 1},
    {"B", 2}
};

var dict2 = new Dictionary<string, int>
{
    {"B", 3},
    {"C", 4}
};

dict1.Merge(dict2, (oldValue, newValue) => oldValue + newValue);

// dict1 now contains: {"A": 1, "B": 5, "C": 4}

5. Converting to ReadOnlyDictionary

If you need to expose a dictionary but prevent modifications, converting it to a ReadOnlyDictionary<TKey, TValue> ensures data integrity.

using System.Collections.ObjectModel;

public static ReadOnlyDictionary<TKey, TValue> AsReadOnly<TKey, TValue>(
    this Dictionary<TKey, TValue> dictionary)
{
    return new ReadOnlyDictionary<TKey, TValue>(dictionary);
}

Usage:

var config = new Dictionary<string, string>
{
    {"AppMode", "Production"}
};

var readOnlyConfig = config.AsReadOnly();
// readOnlyConfig is now immutable

Conclusion

By leveraging extension methods, we can significantly enhance the functionality of dictionaries in C#. These methods improve code readability, maintainability, and efficiency while reducing boilerplate code. Whether you're safely retrieving values, merging dictionaries, or enforcing immutability, these extension methods will streamline your development process.