Click here to Skip to main content
15,886,065 members
Articles / Programming Languages / C#
Article

KeyedList, Extending the KeyedCollection

Rate me:
Please Sign up or sign in to vote.
4.11/5 (5 votes)
25 Sep 2008CDDL2 min read 41.1K   176   26   4
An attempt to offer an alternative to the generic KeyedCollection.

Introduction

This an attempt to offer an alternative to the generic KeyedCollection for ease of use.

Background

I'm a fan of the KeyedCollection. Simply because, in a simple way, it resembles how a table in a database works. The objects in the KeyedCollection contain their key values. This makes it a good candidate for caching and handling business data in memory in a database-like manner.

However, a few thing are annoying when dealing with the KeyedCollection:

  • It's abstract, so you'll have to make an implementation to use it.
  • Unlike tables from a database, you can use only one value as your key.

The primary objective

The primary objective of the KeyedList project is to make a more easy-to-use version of the Generic KeyedCollection, that can be used like this:

C#
KeyedList<string, MyClass> list = new KeyedList<string, MyClass>();
if(list.Contains("key"))
{
    MyClass item = list["key"];
}

Using the code

The KeyedCollection is abstract, and requires an implementation to work; more specifically, you'll have to implement a method GetKeyForItem() that will provide a key for the KeyedCollection for the items in the list.

The KeyedList is, in fact, an implementation of the KeyedCollection, but it offers three alternate ways to let the user provide keys for the chosen item.

  1. By passing in a delegate on instantiation:
  2. C#
    KeyedList<string, MyClass> list = 
       new KeyedList<string, MyClass>(x => x.KeyValue);
    
    // or if you don't like the lampda
    KeyedList<string, MyClass> list = 
       new KeyedList<string, MyClass>( delegate(MyClass x){ return x.Keyvalue; } );
  3. Implementing an interface on the target class:
  4. C#
    class MyClass : IKeyedItem<string>  
    {
        string IKeyedItem<string>.Key     
        {        
            get { return this.KeyValue; }  
                }  
    }
    
    KeyedList<string, MyClass> list = new KeyedList<string, MyClass>(); 
    // etc..
  5. Or finally, by decorating the "Key" property with a DataObjectField attribute:
  6. C#
    class MyClass : IKeyedItem<string>  
    {      
        [DataObjectField(true)]      
        public string KeyValue { get; set; }  
    }  
    
    KeyedList<string, MyClass> list = new KeyedList<string, MyClass>();  
    // etc..

When the key is a combination of values

Then what? Today's Dictionarys and KeyedCollections do not offer a straightforward solution. Let's imagine we have a table that holds order lines... the key would usually be a combination of an OrderId and a LineNumber. The key is only unique when you combine these values. How do you represent that structure using a Dictionary to enforce the uniqueness?

C#
// I was goingfor something like this:

KeyedList<int, string, MyClass> list = new KeyedList<int, string, MyClass>();
if(list.Contains(2, "key"))
{
    MyClass item = list[2,"key"];
}
//  etc ...

I have a suggestion on how to resolve this issue. By using a lightweight generic structure to hold the values as if they were one, and at the same time, providing its own comparer for the Dictionary.

C#
public struct Key<T1, T2> : IEquatable<Key<T1, T2>>
{
      public Key(T1 value1, T2 value2)
    {
               // ...
    }
}

class KeyEqualityComparer<T1, T2> : EqualityComparer<Key<T1, T2>>
{
    // ...
}

You can actually use it directly with a normal Dictionary, like this:

C#
Dictionary<Key<int, int>, MyClass> dictionary = 
  new Dictionary<Key<int, int>, MyClass>(Key<int, int>.Comparer);
// etc..
    
MyClass item = dictionary[new Key(123, 456)];

However, I find it more elegant and easy to use to have it embedded directly in the KeyedList itself.

If you have inputs or feel like adding, correcting, or improve the code, please join the project at Codeplex.

Points of interest

I find that caching more and more data in a more and more complex form seems to be a trend. For that reason, I applaud whenever new and interesting methods and technologies that make this easier comes along... first, the anonymous methods, and later, Lambda expressions and LINQ for Objects. However, I always prefer simple objects over ADO DataSets and DataTables to hold my data in memory; they are simply too heavy and too slow if your data reaches certain amounts. So, out of necessity, I made this implementation.

History

None so far.

License

This article, along with any associated source code and files, is licensed under The Common Development and Distribution License (CDDL)


Written By
Software Developer (Senior) Enyosoft
Denmark Denmark
Software designer/developer with specialization in distributed applications, E-commerce and MS Dynamics Integration using Microsoft .NET Technologies.

Software Design and Development since 1999.
.NET since 2001

Comments and Discussions

 
GeneralMultiple keys Pin
Paul B.29-Sep-08 7:52
Paul B.29-Sep-08 7:52 
GeneralRe: Multiple keys Pin
Rune Baess29-Sep-08 9:33
Rune Baess29-Sep-08 9:33 
GeneralRe: Multiple keys Pin
Rune Baess29-Sep-08 9:51
Rune Baess29-Sep-08 9:51 
Actually when I think about it for a while .... I now struggle to find a valid reason to implement specific collections in general business development. I find that Genric Lists, Dictionaries etc. are fullfilling every need, So why bother?
- Because the 10+ years OOP books preach it?

Anyway, one of the main reasons I made this contribution was precisely to avoid these collection implementations ... Wink | ;)
GeneralRe: Multiple keys Pin
Paul B.30-Sep-08 3:55
Paul B.30-Sep-08 3:55 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.