Generic factory and repositories: Part 2 revisited
This post is part of a series:
- Generic factory and repositories: Part 2 revisited
- Generic factory and repositories: Part 2
- Generic factory and repositories: Part 1
- WCSF, Repositories and Unit of Work?
In Part 2 I discussed my implementation for a SimpleRepositoryFactory. I said that I wasn’t quite happy with the implementation of the factory class, as I would have to adjust my Create() method every time I would add a new repository to the project. At first I was looking for a solution that would let me pass a typeof() into the generic parameter of the InternalRepositoryFactory. For example, I wanted to do something like:
InternalRepositoryFactory<typeof(I), typeof(C)>.Create();
Of course this doesn’t work. Generics need to be resolved at compile time and therefore it’s impossible to create the code I wanted. Or is it?
There is one way of dynamically inserting types into a generic class and/ or method during runtime: reflection! I might be a bit of a nerd, but I love working with reflection. It can do everything! This doesn’t mean I use it inappropriately, I just happen to like the challenge of diving into completely unreadable code and making stuff work!
I managed to adjust my SimpleRepositoryFactory in such a way that I would never need to touch the Create() method again. Even if I add new repositories to the project at a later stage!
public static class SimpleRepositoryFactory
{
private static Dictionary<Type, Type> repositoryTypes =
new Dictionary<Type,Type>()
/// <summary>
/// Creates repository object based on its interface
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="args"></param>
/// <returns></returns>
public static T Create<T>(params object[] args)
{
if (repositoryTypes.ContainsKey(typeof(T)))
{
// Create InternalRepositoryFactory<I, C>.
Type internalFactory =
typeof(InternalRepositoryFactory<,>);
internalFactory = internalFactory.MakeGenericType(
typeof(T), repositoryTypes[typeof(T)]);
// Get the Create() method from the
// InternalRepositoryFactory.
MethodInfo method = internalFactory.GetMethod(
"Create", BindingFlags.Static |
BindingFlags.NonPublic);
// Invoke the Create() method and return the result.
// For some reason I need to wrap 'args' into a new
// object[]?
return (T)method.Invoke(
internalFactory, new object[] {args});
}
else
{
throw new Exception("Type: " + typeof(T)
+ " does not exist in dictionary. Register"
+ " the type mappings first by using the"
+ " RegisterTypeMapping method.");
}
}
/// <summary>
/// Registers the repository types, marking them as
/// available to use with the RepositoryFactory.
/// </summary>
/// <typeparam name="I">Interface type of object.</typeparam>
/// <typeparam name="C">Concrete type of object.</typeparam>
public static void RegisterTypeMapping<I, C>()
{
// Only add the type mapping if it doesn't exist.
if (!typeMapping.ContainsKey(typeof(I)))
{
typeMapping.Add(typeof(I), typeof(C));
}
}
}
There are multiple downsides to this code.
Even though I don’t have to touch the Create() method any more, I have to maintain the internal dictionary with definitions. I have moved the problem to a different area in my code. However, the positive side of this is that I can’t break the implementation by accident. If I need to be able to instantiate a new repository, I will add a new definition to the dictionary, using the RegisterTypeMapping() method.
Another downside is that I’ve made the code a lot more complex! This does not improve readability or maintainability at all! Imagine a colleague, unschooled in the ways of reflection, needs to make changes to this code while I am on holidays… the poor bastard would have a very hard time trying to figure it all out!
I can imagine the performance takes a hit as well. I have no clue how much, as I haven’t bothered to measure. However, I think we can all agree that using reflection to resolve types and invoke methods is a bit more costly than simply invoking a method with generics.
I have no idea whether I should use this code or not. I’ve wrote it, I’ve seen it works and I enjoyed the challenge of figuring it out, but all the potential downsides make me scratch my head whether or not I should revert the code back to the way it was. I did write this post in case you, as reader, might really need to do something similar. Therefore I will let you make up your own mind and I won’t tell you what’s right or wrong. Just remember to sit down and think it over again when you suspect you need to resolve generics dynamically at runtime!
Lastly, I’d like to point out that I’ve moved far away from my original intent of developing a factory to create repositories, instead it has become a very generic class that can instantiate any sort of object as long as it implements an interface that can be returned. I’m not even sure if it can actually be classified as a factory pattern any more. SimpleRepositoryFactory seems a very inadequate name as it does not describe the actual implementation!
