istead of using Dictionary I want some type of collection class that can use a property of the value as the key, is there something like this?
views:
104answers:
3Use a normal one, and when you set the key value pair, specify the property of the value you are interested in.
That was too easy, I must be misunderstanding your request.
Maybe you wanted to use an arbitrary property later rather than at input time. In that case, I think you would have to use multiple dictionary objects (perhaps tied together in a helper class).
Yes, there is - System.Collections.ObjectModel.KeyedCollection<TKey, TValue>
.
That's abstract, and there are no concrete derived classes in the framework as far as I can see, but all you need to implement is GetKeyForItem
as far as I can see. For example, you could do this with a delegate:
public class DelegatingKeyedCollection<TKey, TItem> : System.Collections.ObjectModel.KeyedCollection<TKey, TItem>
{
private readonly Func<TItem, TKey> keySelector;
public DelegatingKeyedCollection(Func<TItem, TKey> keySelector)
{
this.keySelector = keySelector;
}
protected override TKey GetKeyForItem(TItem item)
{
return keySelector(item);
}
}
KeyedCollection as Jon Skeet says is the obvious candidate.
A few random remarks about this class:
You will of course want the property that you use as the key to be readonly.
Its method
Contains(TItem item)
is inherited fromCollection<T>
, and is implemented by iterating through the collection. This can therefore be much slower thanContains(TKey key)
. It's too easy for developers to make the mistake of using the wrong overload, so it may be worth considering implementing your ownContains(TItem item)
method:public new bool Contains(TItem item) { if (item == null) throw new ArgumentNullException("item"); return this.Contains(GetKeyForItem(item)); }
Unlike an IDictionary, it doesn't have a method
TryGetValue
. This can be useful and it might be worth implementing your own:public bool TryGetValue(TKey key, out TItem item) { // If the dictionary exists, use it if (Dictionary != null) return Dictionary.TryGetValue(key, out item); // Else do it the hard way if (!this.Contains(key)) { item = default(TItem); return false; } item = this[key]; return true; }
It doesn't support enumeration of the keys, which can be useful:
public IEnumerable<TKey> GetKeys() { foreach (TItem item in this) { yield return GetKeyForItem(item); } }
Serialization can be inefficient, as it will serialize both its internal list and its internal dictionary. You can get round this if you need to by implementing custom serialization.