jscarle
jscarle

Reputation: 1305

ReadOnlyDictionary<TKey, TValue> with a ReadOnlyCollection<T>

I have a bunch of classes that need to return properties as ReadOnlyCollection<T>s, which works well when they're just List<T>s, however, things get really sloppy with than list is inside a Dictionary<TKey, TValue>.

================================================

For example, this is a typical List that I return as a ReadOnlyCollection:

    private readonly List<string> _encryptionKeys;
    public ReadOnlyCollection<string> EncryptionKeys => _encryptionKeys.AsReadOnly();

================================================

However, this is the convulation I need to do for a ReadOnlyDictionary<TKey, TValue>:

    private readonly ReadOnlyDictionary<string, ReadOnlyCollection<string>> _attributes;
    public ReadOnlyDictionary<string, ReadOnlyCollection<string>> Attributes => _attributes;

... using a temporary variable:

        Dictionary<string, List<string>> attributes = new Dictionary<string, List<string>>();

... to which I add values and its lists, I then build my property:

        Dictionary<string, ReadOnlyCollection<string>> readonlyListDictionary = new Dictionary<string, ReadOnlyCollection<string>>();
        foreach (string key in attributes.Keys)
            readonlyListDictionary.Add(key, attributes[key].AsReadOnly());
        _attributes = new ReadOnlyDictionary<string, ReadOnlyCollection<string>>(readonlyListDictionary);

================================================

Anyone have any suggestions?

Upvotes: 0

Views: 242

Answers (2)

Slava Knyazev
Slava Knyazev

Reputation: 6081

Linq can do the heavylifting for you.

Dictionary<string, List<string>> input = new Dictionary<string, List<string>>();
ReadOnlyDictionary<string, ReadOnlyCollection<string>> output = new ReadOnlyDictionary<string, ReadOnlyCollection<string>>(dict.ToDictionary(kv => kv.Key, kv => kv.Value.AsReadOnly()));

Upvotes: 0

Charlieface
Charlieface

Reputation: 71364

Make it an extension method, then you don't have to think about it the whole time:

public static ReadOnlyDictionary<TKey, ReadOnlyCollection<TValue>> AsReadOnly<TKey, TValue>(this Dictionary<TKey, List<TValue>> source)
{
    return new ReadOnlyDictionary<TKey, ReadOnlyCollection<TValue>>(
        new Dictionary<TKey, ReadOnlyCollection<TValue>>(
        source.Select(kvp =>
            new KeyValuePair<TKey, ReadOnlyCollection<TValue>>(kvp.Key, kvp.Value.AsReadOnly())
    ));
}

Although, the constructor that takes IEnumerable<KeyValuePair> is only available in .NET 5. So in earlier versions we would have to foreach. This option may also be more performant as we pre-size the dictionary

public static ReadOnlyDictionary<TKey, ReadOnlyCollection<TValue>> AsReadOnly<TKey, TValue>(this Dictionary<TKey, List<TValue>> source)
{
    var dict = new Dictionary<TKey, ReadOnlyCollection<TValue>>(source.Count);
    foreach (var kvp in source)
        dict[kvp.Key] = kvp.Value.AsReadOnly();
    return new ReadOnlyDictionary<TKey, ReadOnlyCollection<TValue>>(dict);
}

Just use it like you use the other AsReadOnly extension.

Upvotes: 1

Related Questions