Skip to content

Instantly share code, notes, and snippets.

@hanswolff
Last active August 29, 2015 14:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hanswolff/90896c0c2ed66f94c29a to your computer and use it in GitHub Desktop.
Save hanswolff/90896c0c2ed66f94c29a to your computer and use it in GitHub Desktop.
Very simple dependency injection framework (licensed under MIT license or do what you like with it)
//// Example:
//
// using (var context = new MiniInjectionContext())
// {
// context.Register<IMyInterfaceType>(c => new MyClassImplementingInterface());
//
// var instance = context.Get<IMyInterfaceType>();
// }
//}
using System;
using System.Collections.Generic;
using System.Linq;
public class MiniInjectionContext : IInjectionContext
{
private readonly Dictionary<Type, Func<IInjectionContext, object>> _actions;
public MiniInjectionContext()
{
_actions = new Dictionary<Type, Func<IInjectionContext, object>>();
}
public MiniInjectionContext(MiniInjectionContext parentContext)
{
if (parentContext == null) throw new ArgumentNullException("parentContext");
_actions = parentContext._actions.ToDictionary(x => x.Key, x => x.Value);
}
public void Dispose()
{
// just for convenience to create scopes with "using"
}
public T Get<T>() where T : class
{
return (T) Get(typeof (T));
}
public object Get(Type type)
{
object result;
if (type.IsInterface)
{
result = TryGetInterface(type);
if (result == null)
throw new InvalidOperationException(
String.Format("Type '{0}' not registered for Get(), please use Register<T> first", type.FullName));
return result;
}
result = TryCreateFromConstructor(type);
if (result == null)
throw new InvalidOperationException(
String.Format("Type '{0}' cannot be instantiated as it must have a constructor with only interface parameters". type.FullName));
return result;
}
public T TryGet<T>() where T : class
{
return (T)TryGet(typeof (T));
}
public object TryGet(Type type)
{
if (type.IsInterface)
{
return TryGetInterface(type);
}
return TryCreateFromConstructor(type);
}
private object TryGetInterface(Type type)
{
Func<IInjectionContext, object> func;
if (!_actions.TryGetValue(type, out func))
return null;
return func(this);
}
private object TryCreateFromConstructor(Type type)
{
foreach (var ci in type.GetConstructors()
.Where(x => !x.IsGenericMethod)
.Where(x => x.GetParameters().All(p => p.ParameterType.IsInterface || p.ParameterType == typeof(MiniInjectionContext)))
.OrderBy(x => x.GetParameters().Length))
{
var parameters = ci.GetParameters().Select(p =>
{
if (p.ParameterType == typeof (MiniInjectionContext) || p.ParameterType == typeof (IInjectionContext))
return this;
return Get(p.ParameterType);
}).ToArray();
return ci.Invoke(parameters);
}
return null;
}
public void Register<T>(Func<IInjectionContext, T> createFunc)
{
if (createFunc == null) throw new ArgumentNullException("createFunc");
if (!typeof(T).IsInterface)
throw new InvalidOperationException(String.Format("Generic type <T> for Register<T> must be an interface (but type was: {0})", typeof(T).FullName));
Func<IInjectionContext, object> registerAction = c => createFunc(c);
_actions[typeof(T)] = registerAction;
}
public IInjectionContext CreateScope()
{
return new MiniInjectionContext(this);
}
}
public interface IInjectionContext : IDisposable
{
T Get<T>() where T : class;
object Get(Type type);
T TryGet<T>() where T : class;
object TryGet(Type type);
void Register<T>(Func<IInjectionContext, T> createFunc) where T : class;
IInjectionContext CreateScope();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment