This is a simple IoC Container.
Last year, I was assigned to develop an IoC container for R&D purposes which made me start working with IoC Containers. I share with you here part of it as I think it might help you a lot when you develop your own container.
The Inversion of Control (IoC) and Dependency Injection (DI) patterns are all about eliminating dependencies from your code. Dependency Injection is well-known as “Inversion of Control” whose principle is – “Don’t call us, we’ll call you”. So we can say that IoC is the principle whereas DI is the way of implementation. There are three popular ways of Inversion of Control, namely:
- Constructor Injection
- Method Injection
- Property Injection
I am not going to discuss about IoC or DI, rather I want to show how to implement your own IoC Container. However, if you want to know the details about IoC and DI, please have a look at this link.
Let's move to our code portion:
public static class IoC
{
private static readonly IDictionary<Type,
Type> types = new Dictionary<Type, Type>();
private static readonly IDictionary<Type,
object> typeInstances = new Dictionary<Type, object>();
public static void Register<TContract, TImplementation>()
{
types[typeof(TContract)] = typeof(TImplementation);
}
public static void Register<TContract, TImplementation>(TImplementation instance)
{
typeInstances[typeof(TContract)] = instance;
}
public static T Resolve<T>()
{
return (T)Resolve(typeof(T));
}
public static object Resolve(Type contract)
{
if (typeInstances.ContainsKey(contract))
{
return typeInstances[contract];
}
else
{
Type implementation = types[contract];
ConstructorInfo constructor = implementation.GetConstructors()[0];
ParameterInfo[] constructorParameters = constructor.GetParameters();
if (constructorParameters.Length == 0)
{
return Activator.CreateInstance(implementation);
}
List<object> parameters = new List<object>(constructorParameters.Length);
foreach (ParameterInfo parameterInfo in constructorParameters)
{
parameters.Add(Resolve(parameterInfo.ParameterType));
}
return constructor.Invoke(parameters.ToArray());
}
}
}
Now from your bootstrapper class, you need to register your class like:
Service svc= new Service ();
IoC.Register<IService , Service >(svc);
On subsequent classes, you just need to inject the Interface or class that you register like:
private IService currentSvc = null;
public LoginServices(IService submittedService)
{
this.currentSvc =submittedService;
}
Very very simple!!!! We love simple, don’t we?
Updated: 19 March 2012
Example: Say this is my Interface
:
public interface ILogger
{
void Log(string submittedMsg);
}
The Logger
class implements this interface.
public class Logger :ILogger
{
public void Log(string submittedMsg)
{
if (!string.IsNullOrEmpty(submittedMsg))
{
Console.WriteLine(string.Format("[{0}] {1}\r\n", DateTime.Now, submittedMsg));
Console.Read();
}
}
}
In this ConsoleLogger
class, I inject the ILogger
to its constructor.
public class ConsoleLogger
{
private ILogger logger = null;
public ConsoleLogger(ILogger submittedLogger)
{
this.logger = submittedLogger;
this.DisplayMessage();
}
public void DisplayMessage()
{
logger.Log("Hi..See it is working!!");
}
}
Register
and Resolve
options:
class Program
{
static void Main(string[] args)
{
IoC.Register<ILogger, Logger>();
IoC.Register<ConsoleLogger, ConsoleLogger>();
ConsoleLogger objCOnsoleLogger=IoC.Resolve<ConsoleLogger>();
}
}