Ready to Use Dictionary for Objects of Different Types

March 31st 2014 .NET Framework

Recently a colleague of mine mentioned that he has just learned about KeyedByTypeCollection, although it has been included with .NET framework since .NET 3.0. I'm writing this post, because I didn't know about it until that day, either. This leads me to believe that there must be many more developers out there who aren't aware of this niche class being readily available.

Unlike other generic collections, it provides a simple way of storing objects of multiple different types in a single collection, still being able to retrieve them in a strongly typed manner. Admittedly, it's not a common requirement, but there are scenarios in which such a functionality is extremely useful and having a class for it in .NET framework is really nice. Let me present two such scenarios that have come up in my daily work lately.

Designing a data access layer usually also means creating a data context or repository service class, which provides access to repositories of different entity types. This could be a typical repository service interface:

public interface IRepositoryService
{
    IRepository<Player> Players { get; }
    IRepository<Game> Games { get; }
    IRepository<Session> Sessions { get; }
    IRepository<Round> Rounds { get; }
}

Instead of having a separate private field for each entity repository, they can all be stored in a KeyedByTypedCollection and retrieved from it in individual properties:

private KeyedByTypeCollection<object> _repositories;

public IRepository<Player> Players
{
    get
    {
        return _repositories.Find<IRepository<Player>>();
    }
}

This makes it really easy to implement a generic method for accessing repositories based on their entity type, alongside the strongly typed properties or even instead of them:

public IRepository<T> GetRepository<T>()
{
    return _repositories.Find<IRepository<T>>();
}

In Workflow Foundation extensions can be used to provide additional functionalities when hosting workflows, either to activities or during the persistence process. The IWorkflowInstanceExtension interface allows individual extensions to return additional extensions, they require to function correctly.

The handling of these extensions can again be internally implemented very elegantly using a KeyedByTypeCollection:

private KeyedByTypeCollection<object> _extensions = new KeyedByTypeCollection<object>
{
    new PersistenceExtension(),
    new ActivityExtension()
};

public IEnumerable<object> GetAdditionalExtensions()
{
    return _extensions;
}

public void UseIndividualExtensions()
{
    var persistenceExtension = _extensions.Find<PersistenceExtension>();
    var activityExtension = _extensions.Find<ActivityExtension>();
}

Both of the above examples could of course just as well be implemented without KeyedByTypeCollection, but it wouldn't be as elegant and it would require more code. As I often say, know the tools you are using, .NET framework base class library in this case.

Copyright
Creative Commons License