Click here to Skip to main content
15,888,984 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I suspect there is no quick answer to this, but I'll ask anyway.

I have a class that has:

C#
private Dictionary<string,string> _records = new Dictionary<string,string>();

I would like to expose this to another class but don't want this other class to be able to modify the dictionary in any way - i.e. I don't want it to be able to assign a different dictionary and I don't want it to be able to modify the contents of the existing dictionary.

The number of entries in the dictionary is low - never more than the low tens - so performance is not an issue.

I'm not sure how to get the compiler version, but I am targeting .NET 4.5.2. I seem to have all modern syntax I read about with some exceptions, such as named tuple fields, so I think that puts me on C# 5 (or I could be talking rubbish)?

What is the best way of doing this?

Incidentally, in this particular case, I have a fair amount of flexibility about how these two classes interact. In particular, it would be fine if I could just return an unmodifiable List<string> of the keys in the dictionary. Then I could just add another function to return the value for a specified key.

I could also ditch the Dictionary<string,string> altogether.

What I have tried:

I have done quite a bit of Googling on this subject, but there just seems to be a tonne of contradictory information.

Allowing some form of iteration over a privately maintained collection seems like such a common requirement that I am surprised not to have found an accepted pattern or set of best practices for doing this.
Posted
Updated 28-Apr-17 3:20am
Comments
Richard MacCutchan 28-Apr-17 6:07am    
You could either add some methods to your class to allow the other class access to the content. Or, create a get method that returns a temporary copy of the dictionary.
CHill60 28-Apr-17 6:09am    
Beat me to it! A virtual 5*
Richard MacCutchan 28-Apr-17 6:12am    
Ha, my guessing is faster than yours. :)

 
Share this answer
 
Quote:
In particular, it would be fine if I could just return an unmodifiable List<string> of the keys in the dictionary. Then I could just add another function to return the value for a specified key.

That sounds like the way to go, since it will avoid creating a copy of the dictionary on every access.

I'd be inclined to have the container class implement IReadOnlyDictionary(TKey, TValue)[^]:
C#
public class Foo : IReadOnlyDictionary<string, string>
{
    private readonly Dictionary<string,string> _records = new Dictionary<string,string>();
    
    public int Count => _records.Count;
    
    // The Dictionary.Keys and Dictionary.Values collections are read-only, so this is OK:
    
    public IEnumerable<string> Keys => _records.Keys;
    
    public IEnumerable<string> Values => _records.Values;
    
    public string this[string key] => _records[key];
    
    public bool ContainsKey(string key) => _records.ContainsKey(key);
    
    public bool TryGetValue(string key, out string value) => _records.TryGetValue(key, out value);
    
    public IEnumerator<KeyValuePair<string, string>> GetEnumerator() => _records.GetEnumerator();
    
    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}

NB: You might be tempted to just cast the _records field to an IReadOnlyDictionary<string, string> and return that. But that wouldn't prevent the calling code from casting it back to a Dictionary<string, string> and modifying it.

Depending on your requirements, you might also want to take a look at the Immutable Collections[^] package.
 
Share this answer
 
Comments
Patrick Skelton 28-Apr-17 10:48am    
That is what I was looking for, Richard! Somewhere, buried in my fuzzy memory, was something close to what you've posted above. I didn't go ahead because I had been confused by posts talking about exactly the problem you mention, namely the client being able to cast to Dictionary<K,V>.

Thank you very much!

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900