IOC Containers - Part 2

Saturday, November 15, 2008

My initial IOC container was an automatic factory. When GetInstance was called it executed the stored factory method and returned. You could technically put anything you wanted into the factory method, including a singleton instance or a database call, but it is no better than a standard factory method.

While looking at some of the IOC containers listed in my last post, I noticed the user could select the lifespan of each type. So, I went back to the workbench.



I have abstracted out the lifespan from the repository, through the IRepositoryServiceProvider interface. This change also opens up the possibility for creating custom lifespans.

Usage:

var r = new Repository();
r.RegisterServiceProvider(new FactoryServiceProvider());
r.Register<IMyClass, FactoryServiceProvider>(() => new MyClass("a"));
IMyClass m = r.GetInstance<IMyClass>();

Code:

public delegate object FactoryDelegate();
public delegate T FactoryDelegate<T>();

public interface IRepositoryServiceProvider : IServiceProvider
{
void RegisterService(Type targetType, FactoryDelegate factoryMethod);
}

public class RepositoryPlusOne
{
private readonly Dictionary<Type, IRepositoryServiceProvider> providers =
new Dictionary<Type, IRepositoryServiceProvider>();
private readonly Dictionary<Type, IRepositoryServiceProvider> types =
new Dictionary<Type, IRepositoryServiceProvider>();

public void Register<T, U>(FactoryDelegate<T> factoryMethod)
where T : class
where U : IRepositoryServiceProvider
{
Type u = typeof(U);
Type t = typeof(T);

if (!providers.ContainsKey(u)) throw new ArgumentException("Unregistered Provider", "U");

providers[u].RegisterService(t, () => factoryMethod());
types.Add(t, providers[u]);
}

public void RegisterServiceProvider(IRepositoryServiceProvider provider)
{
providers.Add(provider.GetType(), provider);
}

public TService GetInstance<TService>() where TService : class
{
Type t = typeof(TService);
if (!this.factories.ContainsKey(t)) return default(TService);
return this.factories[t]() as TService;
}
}

public class FactoryServiceProvider : IRepositoryServiceProvider
{
private readonly Dictionary<Type, FactoryDelegate> factories =
new Dictionary<Type, FactoryDelegate>();

#region IRepositoryServiceProvider Members

public void RegisterService(Type targetType, FactoryDelegate factoryMethod)
{
factories.Add(targetType, factoryMethod);
}

#endregion

#region IServiceProvider Members

public object GetService(Type serviceType)
{
return (factories.ContainsKey(serviceType)) ? factories[serviceType]() : null;
}

#endregion
}

public class SingleServiceProvider : IRepositoryServiceProvider
{
private readonly Dictionary<Type, object> objects =
new Dictionary<Type, object>();

#region IRepositoryServiceProvider Members

public void RegisterService(Type targetType, FactoryDelegate factoryMethod)
{
objects.Add(targetType, factoryMethod());
}

#endregion

#region IServiceProvider Members

public object GetService(Type serviceType)
{
return (objects.ContainsKey(serviceType)) ? objects[serviceType] : null;
}

#endregion
}