Created
August 9, 2017 07:19
-
-
Save audinue/5d42d6fd503135e355eeadf4966f1d7e to your computer and use it in GitHub Desktop.
An automatic dependency injection container.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
public sealed class Container | |
{ | |
private Dictionary<Type, Type> concreteTypes = new Dictionary<Type, Type>(); | |
private Dictionary<Type, object> objects = new Dictionary<Type, object>(); | |
private Type FindConcreteTypeFor(Type type) | |
{ | |
Type concreteType; | |
concreteTypes.TryGetValue(type, out concreteType); | |
if (concreteType != null) | |
return concreteType; | |
try | |
{ | |
concreteType = AppDomain.CurrentDomain.GetAssemblies() | |
.SelectMany(a => a.GetTypes()) | |
.First(t => t != type && type.IsAssignableFrom(t)); | |
concreteTypes[type] = concreteType; | |
return concreteType; | |
} | |
catch (Exception) | |
{ | |
throw new Exception(string.Format("Unable to find concrete type for '{0}'.", type)); | |
} | |
} | |
/// <summary> | |
/// Maps concrete type y to abstract type x. | |
/// </summary> | |
public Container Map(Type x, Type y) | |
{ | |
if (x == null) | |
throw new ArgumentNullException("x"); | |
if (y == null) | |
throw new ArgumentNullException("y"); | |
concreteTypes[x] = y; | |
return this; | |
} | |
/// <summary> | |
/// Maps concrete type Y to abstract type X. | |
/// </summary> | |
public Container Map<X, Y>() | |
{ | |
return Map(typeof(X), typeof(Y)); | |
} | |
/// <summary> | |
/// Maps object y to abstract type x. | |
/// </summary> | |
public Container Map(Type x, object y) | |
{ | |
if (x == null) | |
throw new ArgumentNullException("x"); | |
objects[x] = y; | |
return this; | |
} | |
/// <summary> | |
/// Maps object y to abstract type X. | |
/// </summary> | |
public Container Map<X>(object y) | |
{ | |
return Map(typeof(X), y); | |
} | |
/// <summary> | |
/// Creates an object of the given type. | |
/// </summary> | |
public object Create(Type type) | |
{ | |
if (type == null) | |
throw new ArgumentNullException("type"); | |
object @object; | |
objects.TryGetValue(type, out @object); | |
if (@object != null) | |
return @object; | |
if (type.IsAbstract) | |
return Create(FindConcreteTypeFor(type)); | |
var constructor = type.GetConstructors().First(); | |
@object = constructor.Invoke( | |
constructor.GetParameters() | |
.Select(parameter => Create(parameter.ParameterType)) | |
.ToArray() | |
); | |
objects[type] = @object; | |
return @object; | |
} | |
/// <summary> | |
/// Creates an object of type T. | |
/// </summary> | |
public T Create<T>() | |
{ | |
return (T)Create(typeof(T)); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment