I find myself often faced with this problem: I have a dictionary where the key is some simple numeric ID and the value is an object. The ID is also contained in a specific property of that value object.
Then, I want to be able to deserialize some (format-inflexible) XML that looks like:
<listitem>
<id>20359</id>
<someotherval>foo</someotherval>
</listitem>
<listitem>
...
This requires me to deserialize with a List<V>, and it’s inconvenient to have to manually convert that to a Dictionary<K,V>.
The second issue is with binding. Binding lists require that the source implements ICollection (if I remember correctly), and again it’s a pain to have to manually create a new List<V> and populate it from the Dictionary<K,V>.
My current, fairly ugly but functional solution is to have the following classes:
public abstract class Keyed<KeyType>
{
public KeyType key { get; set; }
}
public class KeyedDictionary<KeyType, ValueType> :
Dictionary<KeyType, ValueType>
where ValueType : Keyed<KeyType>
{
// ...
}
public class KeyedList<KeyType, ValueType> :
IList<ValueType>,
System.Collections.IList
where ValueType : Keyed<KeyType>
{
public readonly KeyedDictionary<KeyType, ValueType> dict =
new KeyedDictionary<KeyType, ValueType>();
// ...
}
This works, but it’s internally large and ugly. Are there any better ways?
EDIT: Here is the solution I’ve settled on.
public interface IKeyed<KeyType>
{
KeyType Key { get; }
}
public class KeyedList<KeyType, ValueType> :
KeyedCollection<KeyType, ValueType>
where ValueType : IKeyed<KeyType>
{
protected override KeyType GetKeyForItem(ValueType item) { return item.Key; }
}
It sounds like the built-in
KeyedCollection<K,I>type might do the trick. It’s an abstract class so you’ll need to derive your own concrete subclass(es), but that’s easy enough.You could create separate specialised implementations tailored to your exact needs, or you could create a single general-purpose version that accepts a key selector delegate as a constructor argument. (The general-purpose version will be marginally less efficient than a specialised version due to the cost of the delegate invocation each time there’s a key lookup.)