Instead of using Dictionary<TKey,TValue>
I want some type of collection class that can use a property of the value as the key, is there something like this?
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 from Collection<T>
, and is implemented by iterating through the collection. This can therefore be much slower than Contains(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 own Contains(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.
Use 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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With