tags:

views:

107

answers:

3

Seems like I forgot a typename ... Something inside my head keeps telling me that I have stumbled across a Dictionary that basicly uses a user-defined Comparer for lookups. But I somehow can't find that class in the depths of .Net anymore.

As I have no real idea how to describe what I am looking for without describing a possible implmenentation, I will also give an example of what I wan't to do.

I am basicly looking for a way to achieve the following (pseudocode):

class CustomId
{
   // [...]
}
class Element
{
   CustomId id;
}
Container<CustomId, Element> myContainer = new Container(myCustomComparer)
myContainer.Add(new Element()) // No key specified
myElement = myContainer[new CustomId(...)]; // Retrieval with custom id

Maybe this technically isn't quite a dictionary, but I hope the idea is clear. Basicly the key is part of the stored element.

+11  A: 

I think you are looking for KeyedCollection<TKey, TItem>. Create a class that inherits from this class and override the GetKeyForItem() method.

Bryan
Wow, so fast that StackOverflow does not even allow to mark it as an answer right now.
Marcus Riemer
+2  A: 

It's actually quite easy. you just have to inherit from KeyedCollection<TKey, TItem>:

public class ElementCollection : KeyedCollection<CustomId, Element>
{
    public override CustomId GetKeyForItem(Element element)
    {
        return element.id;
    }
}
Justin Niessner
Doh! Looks like I'm too slow to type. Leaving here for sample code anyway...
Justin Niessner
It seems like the net result is that you pass an `Element` in as the key to a container, and you get that `Element` from the collection returned. If you already have the `Element`, what is the point?
JohnB
Because you don't already have the Element. You only have the CustomId. The GetKeyForItem method is called internally to check the CustomId you provide against the Elements in the collection...not the other way around.
Justin Niessner
A: 

You could do a couple of things:

Use a simple List and use Linq to retrieve objects by CustomID:

var elements = myContainer.Where(e=>e.CustomID == new CustomID(...)).ToList();

Or, extend the generic Dictionary class to provide an Add overload that knows how to project the key from the given value:

public class AutoDictionary<K,V> : Dictionary<K,V>
{
   public Func<V,K> KeyGenerator { get; set; }
   public void Add(V value)
   {
      Add(KeyGenerator(V),V);
   }
}

...

var myContainer = new AutoDictionary<CustomId, Element>();
myContainer.KeyGenerator = e=> e.id;
myContainer.Add(myElement);
var elementFromDictionary = myContainer[myElement.id]; //will be the same instance as myElement
KeithS