Geeks With Blogs
New Things I Learned

A little over 2 years ago, I saw my peer’s code that uses the KeyedCollection<TKey, TItem> class.  I never seen it before, and it is actually a pretty nice class.  It is essentially a dictionary class, but with the stipulation that the key for each item added to the dictionary can be retrieved from the item itself. 

With a Dictionary, every time we wanted to add a new item into it, we have to call its Add method, which accepts 2 parameters, the key for the item and the item itself.  In most cases, the key already is in the item, so we’re just reduplicating it.  This KeyedCollection class provides a shortcut since we can just provide it a method so it can get the key for each item added automatically.

The following code show how Dictionary and KeyedCollection can be used:

// Class to contain data stuff
public class MyData
{
   public int Id { get; set; }
   public string Data { get; set; }
 }

// KeyedCollection is an abstract class, so have to derive
public class MyDataKeyedCollection : KeyedCollection<int, MyData>
{
   protected override int GetKeyForItem(MyData item)
   {
      return item.Id;
   }
}

private void Test()
{
   MyData temp, md = new MyData() { Id = 1, Data = "Test" };
   
   // Using a Dictionary
   Dictionary<int, MyData> dict = new Dictionary<int, MyData>();
   dict.Add(md.Id, md);  // Add to dictionary
   temp = dict[1];       // Retrieve

   // Using KeyedCollection
   KeyedCollection<int, MyData> keyd = new MyDataKeyedCollection();
   keyd.Add(md);         // Add to KeyedCollection
   temp = keyd[1];       // Retrieve
}

As you can see, usage is very, very similar to a Dictionary, with the only difference that the Add method only accepts 1 parameter.  Retrieval is exactly the same.  However, since KeyedCollection is an abstract class, you cannot use it directly; you have to derive from it and use your derived class – that’s why I created the MyDataKeyedCollection class.  This MyDataKeyedCollection class has to override the GetKeyForItem method (which is declared as an abstract method in the base class) so you can retrieve the key for the given item.  For me this is somewhat of a deal breaker – I have to always derive from it – there’s no way to use it easily, like a typical collection class.

So my next step is to try to make it easier to consume… thus I created my KeyedCollectionEx class.

public class KeyedCollectionEx<TKey, TItem> : KeyedCollection<TKey, TItem>
{
   private Func<TItem, TKey> _getKeyForItemDelegate;
   public KeyedCollectionEx(Func<TItem, TKey> getKeyForItemDelegate) : base()
   {
      if (getKeyForItemDelegate == null)
         throw new ArgumentNullException("Delegate passed can't be null!");

      _getKeyForItemDelegate = getKeyForItemDelegate;
   }

   protected override TKey GetKeyForItem(TItem item)
   {
      return _getKeyForItemDelegate(item);
   }
}

The constructor now requires a delegate that will get the TKey for the given TItem – I’m using the Func delegate which is in .NET 3.0, so if you’re using .NET 2.0, you need to create your own delegate signature.  With this, my test method becomes as follows:

private void Test2()
{
   MyData temp, md = new MyData() { Id = 1, Data = "Test" };

   // Using KeyedCollectionEx with anonymous delegate
   KeyedCollection<int, MyData> keyd = new KeyedCollectionEx<int, MyData>(delegate(MyData myData) { return myData.Id; });
   keyd.Add(md);         // Add to KeyedCollection
   temp = keyd[1];       // Retrieve

   // Using KeyedCollectionEx with lambda expression
   KeyedCollection<int, MyData> keyd2 = new KeyedCollectionEx<int, MyData>(myData => myData.Id);
   keyd2.Add(md);         // Add to KeyedCollection
   temp = keyd2[1];       // Retrieve
}

I demonstrated how to use it with anonymous methods (so I don’t have to create a method for it), and also how to use it with a lambda expression.  Much simpler, IMHO – no need to create a derived class.  However, I would like this to work with WPF’s data binding – so I’d like further enhance my KeyedCollectionEx class so it can notify WPF when items are being added or removed from it – that’ll be my next post.

Posted on Thursday, January 7, 2010 10:42 AM | Back to top


Comments on this post: Using KeyedCollection<TKey, TItem>

# re: Using KeyedCollection<TKey, TItem>
Requesting Gravatar...
Good article! I like the Extended keyedCollection. Also I find "reduplicating" to be one of the funnier things I've read in a while. cheers.
Left by nice on Sep 06, 2010 8:11 PM

# re: Using KeyedCollection<TKey, TItem>
Requesting Gravatar...
Thank you for posting. It is an additional information for me. Thanks for the read. Liked it. I'm sure to follow up on your post in the future. Great post.
Left by Therapy Programs on Nov 03, 2010 2:27 AM

# re: Using KeyedCollection<TKey, TItem>
Requesting Gravatar...
I would like to thank you for the effort in writing this article. I definitely enjoying every little bit of it and I have you bookmarked to check out new stuff you post.
Left by Xrystiann Mxyzptlk on Nov 03, 2010 2:29 AM

# re: Using KeyedCollection<TKey, TItem>
Requesting Gravatar...
This is really needed to be shared to many readers. Keep on pursuing good things so that you can help many people on their needs suchlike this. You’re a good author.
Left by great essays on Feb 17, 2011 11:39 PM

# re: Using KeyedCollection<TKey, TItem>
Requesting Gravatar...
The KeyedCollection class is a hybrid between a collection based on the IList generic interface and a collection based on the IDictionary generic interface. By default, the KeyedCollection includes a lookup dictionary. Thanks.



Left by Flannel Sheets on Mar 14, 2011 1:21 AM

# re: Using KeyedCollection<TKey, TItem>
Requesting Gravatar...
Been looking for this...! And this is what I searching for ...thanks for sharing the code man... :)
Left by Hosting on Mar 16, 2011 1:20 PM

# re: Using KeyedCollection<TKey, TItem>
Requesting Gravatar...
I've been involved in a lengthy discussion recently at work involving the I Disposable implementation in WCF clients.
Left by chore cards on Mar 18, 2011 9:03 PM

# re: Using KeyedCollection<TKey, TItem>
Requesting Gravatar...
I didn't hear about this before. But Anyways, thanks a lot for posting. I really appreciate it.
Left by One24 on May 25, 2011 5:26 AM

# re: Using KeyedCollection<TKey, TItem>
Requesting Gravatar...
Thank you so much for sharing this one up. I love this blog.
Left by childhood anxiety treatment on Feb 01, 2012 6:09 AM

# re: adopted to work in .net2 vs2008
Requesting Gravatar...
KeyedCollectionEx.cs:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;

namespace Example
{

public class KeyedCollectionEx<TKey, TItem> : KeyedCollection<TKey, TItem>
{
public delegate TKey TgetKeyForItemDelegate(TItem arg1);
private TgetKeyForItemDelegate _getKeyForItemDelegate;

public KeyedCollectionEx(TgetKeyForItemDelegate getKeyForItemDelegate)
: base()
{
if (getKeyForItemDelegate == null)
throw new ArgumentNullException("Delegate passed can't be null!");

_getKeyForItemDelegate = getKeyForItemDelegate;
}

protected override TKey GetKeyForItem(TItem item)
{
return _getKeyForItemDelegate(item);
}
}
/*
* example:
using System.Collections.ObjectModel;
private void Test2()
{
MyData temp, md = new MyData() { Id = 1, Data = "Test" };

// Using KeyedCollectionEx with anonymous delegate
KeyedCollection<int, MyData> keyd = new KeyedCollectionEx<int, MyData>(delegate(MyData myData) { return myData.Id; });
keyd.Add(md); // Add to KeyedCollection
temp = keyd[1]; // Retrieve

// Using KeyedCollectionEx with lambda expression
KeyedCollection<int, MyData> keyd2 = new KeyedCollectionEx<int, MyData>(myData => myData.Id);
keyd2.Add(md); // Add to KeyedCollection
temp = keyd2[1]; // Retrieve
}
*/
}
Left by Shimon Doodkin on Aug 21, 2012 9:41 AM

# re: Using KeyedCollection<TKey, TItem>
Requesting Gravatar...
here's another approach

public abstract class keyeditembase<K>
{
public K key;
public keyeditembase(K key) {this.key = key;}
}


public class KeyedCollectionAA<K, T> : KeyedCollection<K, T> where T : keyeditembase<K>
{
public new bool Add(T item)
{
if (Contains(item.key))
{return false;}// or could throw exception
else
{
base.Add(item);
return true;//or could return the added object
}
}
protected override K GetKeyForItem(T item)
{return item.key;}
}

use like this:

private class mydata: keyeditembase<string>
{
//define stuff

public mydata(string mykeyparameter, other parameters)
: base(mykeyparameter)
{
//do stuff
}
}


Left by stentor on Mar 06, 2016 4:49 PM

Your comment:
 (will show your gravatar)


Copyright © Muljadi Budiman | Powered by: GeeksWithBlogs.net