Created
November 14, 2011 03:24
-
-
Save bryanmenard/1363161 to your computer and use it in GitHub Desktop.
dioc - Dependency injection and Inversion of control
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
// Release under MIT license Copyright (c) 2011 Bryan Menard, http://www.bryblog.com/license.txt | |
using System; | |
using System.Collections; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Reflection; | |
namespace Dioc | |
{ | |
/// <summary> | |
/// Container for components. The container is not a performance superstar, but performs pretty well with | |
/// singleton components. | |
/// </summary> | |
/// <remarks> | |
/// This container is implemented from scratch to avoid having external dependencies to IoC containers like Castle.Windsor. | |
/// </remarks> | |
public class ComponentContainer | |
{ | |
/// <summary> | |
/// All of the registered components | |
/// </summary> | |
private readonly Dictionary<Type, ComponentRegistration> Registrations = new Dictionary<Type, ComponentRegistration>(); | |
/// <summary> | |
/// All of the registered and created singletons | |
/// </summary> | |
private readonly Dictionary<Type, object> Singletons = new Dictionary<Type, object>(); | |
/// <summary> | |
/// Registers a singleton component, created at most once, when requested. | |
/// </summary> | |
/// <param name="parameters">The parameters to inject manually</param> | |
/// <typeparam name="T">The type of the component</typeparam> | |
public void Singleton<T>(Hashtable parameters = null) | |
{ | |
Singleton<T, T>(parameters); | |
} | |
/// <summary> | |
/// Registers a singleton component, created at most once, when requested. | |
/// </summary> | |
/// <param name="parameters">The parameters to inject manually</param> | |
/// <typeparam name="TInterface">The type of the interface</typeparam> | |
/// <typeparam name="TImplementation">The type of the implementation</typeparam> | |
public void Singleton<TInterface, TImplementation>(Hashtable parameters = null) where TImplementation : TInterface | |
{ | |
// Ensure the type was not already registered | |
EnsureNotRegistered(typeof (TInterface)); | |
// Add a registration for that type | |
Registrations.Add(typeof (TInterface), ComponentRegistration.CreateSingleton(typeof (TImplementation), parameters)); | |
} | |
/// <summary> | |
/// Registers a singleton component, created at most once when requested, using the provided factory method | |
/// </summary> | |
/// <param name="factoryMethod">The factory method to use in order to create the component</param> | |
/// <param name="parameters">The parameters to inject manually</param> | |
/// <typeparam name="T">The type of the component</typeparam> | |
public void Singleton<T>(Func<T> factoryMethod, Hashtable parameters = null) | |
{ | |
// Ensure the type was not already registered | |
EnsureNotRegistered(typeof(T)); | |
// Add a registration for that type | |
Registrations.Add(typeof(T), ComponentRegistration.CreateSingleton(typeof(T), () => factoryMethod(), parameters)); | |
} | |
/// <summary> | |
/// Registers a transient component, to be created each time it is requested | |
/// </summary> | |
/// <param name="parameters">The parameters to inject manually</param> | |
/// <typeparam name="T">The type of the component</typeparam> | |
public void Transient<T>(Hashtable parameters = null) | |
{ | |
Transient<T, T>(parameters); | |
} | |
/// <summary> | |
/// Registers a transient component, to be created each time it is requested | |
/// </summary> | |
/// <param name="parameters">The parameters to inject manually</param> | |
/// <typeparam name="TInterface">The type of the interface</typeparam> | |
/// <typeparam name="TImplementation">The type of the implementation</typeparam> | |
public void Transient<TInterface, TImplementation>(Hashtable parameters = null) where TImplementation : TInterface | |
{ | |
// Ensure the type was not already registered | |
EnsureNotRegistered(typeof(TInterface)); | |
// Add a registration for that type | |
Registrations.Add(typeof(TInterface), ComponentRegistration.CreateTransient(typeof(TImplementation), parameters)); | |
} | |
/// <summary> | |
/// Registers a transient component, to be created each time it is requested using the provided factory method | |
/// </summary> | |
/// <param name="factoryMethod">The factory method to use in order to create the component</param> | |
/// <param name="parameters">The parameters to inject manually</param> | |
/// <typeparam name="T">The type of the component</typeparam> | |
public void Transient<T>(Func<T> factoryMethod, Hashtable parameters = null) | |
{ | |
// Ensure the type was not already registered | |
EnsureNotRegistered(typeof(T)); | |
// Add a registration for that type | |
Registrations.Add(typeof(T), ComponentRegistration.CreateTransient(typeof(T), () => factoryMethod(), parameters)); | |
} | |
/// <summary> | |
/// Registers a component by specifying the instance to use | |
/// </summary> | |
/// <param name="instance">The instance to user</param> | |
/// <typeparam name="T">The instance of the component</typeparam> | |
public void Instance<T>(T instance) | |
{ | |
Instance<T, T>(instance); | |
} | |
/// <summary> | |
/// Registers a component by specifying the instance to use | |
/// </summary> | |
/// <param name="instance">The instance to user</param> | |
/// <typeparam name="TInterface">The type of the interface</typeparam> | |
/// <typeparam name="TImplementation">The type of the implementation</typeparam> | |
public void Instance<TInterface, TImplementation>(TInterface instance) where TImplementation : TInterface | |
{ | |
// Ensure the type was not already registered | |
EnsureNotRegistered(typeof(TInterface)); | |
// Add a registration for that type | |
Registrations.Add(typeof(TInterface), ComponentRegistration.CreateInstance(typeof(TImplementation), instance)); | |
} | |
/// <summary> | |
/// Ensure no component of the given type is registered yet | |
/// </summary> | |
/// <param name="type">The type of the component</param> | |
private void EnsureNotRegistered(Type type) | |
{ | |
// Ensure the type was not already registered | |
if (Registrations.ContainsKey(type)) | |
{ | |
throw ComponentResolutionException.AlreadyRegistered(type); | |
} | |
} | |
/// <summary> | |
/// Get a component of the given type | |
/// </summary> | |
/// <param name="parameters">The parameters to inject manually</param> | |
/// <typeparam name="T">The type of the component</typeparam> | |
/// <returns>The component of the requested type</returns> | |
public T Get<T>(Hashtable parameters = null) | |
{ | |
return (T)GetInternal(typeof(T), null, parameters); | |
} | |
/// <summary> | |
/// Get a component of the given type | |
/// </summary> | |
/// <param name="type">The type of the component</param> | |
/// <param name="parameters">The parameters to inject manually</param> | |
/// <returns>The component of the requested type</returns> | |
public object Get(Type type, Hashtable parameters = null) | |
{ | |
return GetInternal(type, null, parameters); | |
} | |
/// <summary> | |
/// Internal method for getting a type by specifying and existing set of pending resolutions, mainly used | |
/// to detect circular dependencies | |
/// </summary> | |
/// <param name="type">The type of the component</param> | |
/// <param name="pendingResolutions">A set of pending resolutions</param> | |
/// <param name="parameters">The parameters to inject manually</param> | |
/// <returns>The component of the requested type</returns> | |
private object GetInternal(Type type, IDictionary<Type, ComponentRegistration> pendingResolutions, Hashtable parameters) | |
{ | |
// Get the registration for the given type | |
ComponentRegistration registration; | |
// Ensure the component is registered | |
if (!Registrations.TryGetValue(type, out registration)) | |
{ | |
throw ComponentResolutionException.NotRegistered(type); | |
} | |
// Try and retrieve the instance as a singleton instance when appropriate | |
if (registration.Singleton) | |
{ | |
object singleton; | |
if (Singletons.TryGetValue(type, out singleton)) | |
return singleton; | |
} | |
object instance; | |
if (registration.Instance != null) | |
{ | |
// Use the instance if provided | |
instance = registration.Instance; | |
} | |
else if (registration.FactoryMethod != null) | |
{ | |
// Use the factory method provided | |
instance = registration.FactoryMethod(); | |
} | |
else | |
{ | |
// Find the constructor for the given type | |
var ctor = GetConstructor(registration.Type); | |
// Ensure there is an eligible constructor | |
if (ctor == null) | |
{ | |
throw ComponentResolutionException.ConstructorNotFound(type); | |
} | |
var dependencies = ctor.GetParameters().ToList(); | |
// Create a dictionary of seen type that are not yet resolved | |
pendingResolutions = pendingResolutions ?? new Dictionary<Type, ComponentRegistration>(); | |
// Add an entry for the current type in the pending resolutions | |
pendingResolutions.Add(type, registration); | |
// The list of resolved dependencies | |
var resolvedDependencies = new object[dependencies.Count]; | |
var currentDependencyIndex = 0; | |
// For every dependency | |
foreach (var dependency in dependencies) | |
{ | |
// Try and get the parameter from the manual parameter list | |
if (parameters != null) | |
{ | |
var argument = parameters[dependency.Name]; | |
if (argument != null && dependency.ParameterType.IsAssignableFrom(argument.GetType())) | |
{ | |
resolvedDependencies[currentDependencyIndex++] = argument; | |
continue; | |
} | |
} | |
// Try and get the parameter from the default parameter list | |
if (registration.Parameters != null) | |
{ | |
var argument = registration.Parameters[dependency.Name]; | |
if (argument != null && dependency.ParameterType.IsAssignableFrom(argument.GetType())) | |
{ | |
resolvedDependencies[currentDependencyIndex++] = argument; | |
continue; | |
} | |
} | |
// The dependency could not be resolved with manually provided parameters. | |
// Resolve it using other components registered | |
var dependencyType = dependency.ParameterType; | |
// Ensure there is no circular dependency | |
if (pendingResolutions.ContainsKey(dependencyType)) | |
{ | |
throw ComponentResolutionException.CircularDependency(type, dependencyType); | |
} | |
try | |
{ | |
// Create an instance of the dependency recursively | |
resolvedDependencies[currentDependencyIndex++] = GetInternal(dependencyType, pendingResolutions, null); | |
} | |
catch (ComponentResolutionException ex) | |
{ | |
// Wrap an throw the exception | |
throw ComponentResolutionException.DependencyResolution(type, ex); | |
} | |
} | |
// Create an instance of the type using the constructor obtained before | |
instance = ctor.Invoke(resolvedDependencies); | |
} | |
// Register the instance as a singleton when appropriate | |
if (registration.Singleton) | |
Singletons.Add(type, instance); | |
// Return the newly created instance | |
return instance; | |
} | |
/// <summary> | |
/// Gets the constructor to use for insantiation | |
/// </summary> | |
/// <param name="type">The type for which to obtain a constructor</param> | |
/// <returns>The constructor to use for instantiation or null if no candidates exist</returns> | |
private static ConstructorInfo GetConstructor(Type type) | |
{ | |
ConstructorInfo ctor = null; | |
int nbParams = -1; | |
// Find the constructor with the most parameters | |
foreach (var constructor in type.GetConstructors()) | |
{ | |
var nbParamsCurrent = constructor.GetParameters().Length; | |
if (nbParamsCurrent > nbParams) | |
{ | |
ctor = constructor; | |
nbParams = nbParamsCurrent; | |
} | |
} | |
return ctor; | |
} | |
} | |
} |
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
// Release under MIT license Copyright (c) 2011 Bryan Menard, http://www.bryblog.com/license.txt | |
using System; | |
using System.Collections; | |
using NUnit.Framework; | |
namespace Dioc | |
{ | |
[TestFixture] | |
public class ComponentContainerTests | |
{ | |
private ComponentContainer Container; | |
[SetUp] | |
public void SetUp() | |
{ | |
Container = new ComponentContainer(); | |
} | |
#region Component structure | |
// Components are defined below | |
// A | |
// B -> (A) | |
// C -> (A, A) | |
// D -> (B, C) | |
// E -> (E) Circular dependency | |
// F -> (G) | |
// G -> (H) | |
// H -> (F) Circular dependency | |
#endregion | |
[Test] | |
public void Get_SimpleTransient_ReturnsInstance() | |
{ | |
Container.Transient<IA, A>(); | |
var instance = Container.Get<IA>(); | |
Assert.That(instance, Is.TypeOf<A>()); | |
} | |
[Test] | |
public void Get_SameTransientTwice_ReturnsDifferentInstances() | |
{ | |
Container.Transient<IA, A>(); | |
var instance1 = Container.Get<IA>(); | |
var instance2 = Container.Get<IA>(); | |
Assert.That(instance1, Is.Not.SameAs(instance2)); | |
} | |
[Test] | |
public void Get_SimpleSingleton_ReturnsInstance() | |
{ | |
Container.Singleton<IA, A>(); | |
var instance = Container.Get<IA>(); | |
Assert.That(instance, Is.TypeOf<A>()); | |
} | |
[Test] | |
public void Get_SameSingletonTwice_ReturnsSameInstance() | |
{ | |
Container.Singleton<IA, A>(); | |
var instance1 = Container.Get<IA>(); | |
var instance2 = Container.Get<IA>(); | |
Assert.That(instance1, Is.SameAs(instance2)); | |
} | |
[Test] | |
public void Get_TransientWithTransientDependencies_ReturnsInstance() | |
{ | |
Container.Transient<IA, A>(); | |
Container.Transient<IB, B>(); | |
var instance = Container.Get<IB>(); | |
Assert.That(instance, Is.TypeOf<B>()); | |
} | |
[Test] | |
public void Get_TransientWithSingletonDependencies_ReturnsSameDependencies() | |
{ | |
Container.Singleton<IA, A>(); | |
Container.Transient<IB, B>(); | |
var instance1 = Container.Get<IB>(); | |
var instance2 = Container.Get<IB>(); | |
Assert.That(instance1, Is.Not.SameAs(instance2)); | |
Assert.That(((B)instance1).A, Is.SameAs(((B)instance2).A)); | |
} | |
[Test] | |
public void Get_SingletonWithTransientDependencies_ReturnsSameInstanceThusSameDependencies() | |
{ | |
Container.Transient<IA, A>(); | |
Container.Singleton<IB, B>(); | |
var instance1 = Container.Get<IB>(); | |
var instance2 = Container.Get<IB>(); | |
Assert.That(instance1, Is.SameAs(instance2)); | |
Assert.That(( (B)instance1 ).A, Is.SameAs(( (B)instance2 ).A)); | |
} | |
[Test] | |
public void Get_Unregistered_ThrowException() | |
{ | |
AssertThrowsWithRootCause(() => Container.Get<IF>(), ComponentResolutionError.NotRegistered); | |
} | |
[Test] | |
public void Get_TransientWithCircularDependency_ThrowsException() | |
{ | |
Container.Singleton<IE, E>(); | |
AssertThrowsWithRootCause(() => Container.Get<IE>(), ComponentResolutionError.CircularDependency); | |
} | |
[Test] | |
public void Get_TransientWithLargeCircularDependency_ThrowsException() | |
{ | |
Container.Singleton<IF, F>(); | |
Container.Singleton<IG, G>(); | |
Container.Singleton<IH, H>(); | |
AssertThrowsWithRootCause(() => Container.Get<IF>(), ComponentResolutionError.CircularDependency); | |
} | |
[Test] | |
public void Get_Instance_ReturnsInstance() | |
{ | |
var expected = new A(); | |
Container.Instance<IA, A>(expected); | |
var actual = Container.Get<IA>(); | |
Assert.That(actual, Is.SameAs(expected)); | |
} | |
[Test] | |
public void Get_TransientWithFactoryMethod_InvokesFactoryMethodEachTime() | |
{ | |
var invocations = 0; | |
var expected = new A(); | |
Container.Transient<IA>(() => { invocations++; return expected; }); | |
var actual1 = Container.Get<IA>(); | |
var actual2 = Container.Get<IA>(); | |
Assert.That(invocations, Is.EqualTo(2)); | |
Assert.That(actual1, Is.SameAs(expected)); | |
Assert.That(actual2, Is.SameAs(expected)); | |
} | |
[Test] | |
public void Get_TransientWithFactoryMethod_InvokesFactoryMethodLazily() | |
{ | |
var invocations = 0; | |
var expected = new A(); | |
Container.Transient<IA>(() => { invocations++; return expected; }); | |
Assert.That(invocations, Is.EqualTo(0)); | |
} | |
[Test] | |
public void Get_SingletonWithFactoryMethod_InvokesFactoryMethodOnce() | |
{ | |
var invocations = 0; | |
var expected = new A(); | |
Container.Singleton<IA>(() => { invocations++; return expected; }); | |
var actual1 = Container.Get<IA>(); | |
var actual2 = Container.Get<IA>(); | |
Assert.That(invocations, Is.EqualTo(1)); | |
Assert.That(actual1, Is.SameAs(expected)); | |
Assert.That(actual2, Is.SameAs(expected)); | |
} | |
[Test] | |
public void Get_SingletonWithFactoryMethod_InvokesFactoryMethodLazily() | |
{ | |
var invocations = 0; | |
var expected = new A(); | |
Container.Singleton<IA>(() => { invocations++; return expected; }); | |
Assert.That(invocations, Is.EqualTo(0)); | |
} | |
[Test] | |
public void Get_WithDefaultParametersForUnregisteredComponent_UsesProvidedParameters() | |
{ | |
// Arrange | |
Container.Transient<IA, A>(); | |
var parameters = new Hashtable { { "manual", "Injected!" } }; | |
Container.Transient<IJ, J>(parameters); | |
// Act | |
var actual = Container.Get<IJ>(); | |
// Assert | |
Assert.That(actual, Is.TypeOf<J>()); | |
Assert.That(( (J)actual ).Manual, Is.EqualTo("Injected!")); | |
} | |
[Test] | |
public void Get_WithDefaultParametersForRegisteredComponent_UsesProvidedParameters() | |
{ | |
// Arrange | |
Container.Transient<IA, A>(); | |
var a = new A(); | |
var parameters = new Hashtable { { "a", a }, { "manual", "Injected!" } }; | |
Container.Transient<IJ, J>(parameters); | |
// Act | |
var actual = Container.Get<IJ>(); | |
// Assert | |
Assert.That(actual, Is.TypeOf<J>()); | |
Assert.That(( (J)actual ).A, Is.SameAs(a)); | |
} | |
[Test] | |
public void Get_WithManualParametersForUnregisteredComponent_UsesProvidedParameters() | |
{ | |
// Arrange | |
Container.Transient<IA, A>(); | |
Container.Transient<IJ, J>(); | |
// Act | |
var actual = Container.Get<IJ>(new Hashtable { { "manual", "Injected!" } }); | |
// Assert | |
Assert.That(actual, Is.TypeOf<J>()); | |
Assert.That(((J)actual).Manual, Is.EqualTo("Injected!")); | |
} | |
[Test] | |
public void Get_WithManualParametersForRegisteredComponent_UsesProvidedParameters() | |
{ | |
// Arrange | |
Container.Transient<IA, A>(); | |
var a = new A(); | |
Container.Transient<IJ, J>(); | |
// Act | |
var actual = Container.Get<IJ>(new Hashtable { { "a", a }, { "manual", "Injected!" } }); | |
// Assert | |
Assert.That(actual, Is.TypeOf<J>()); | |
Assert.That(( (J)actual ).A, Is.SameAs(a)); | |
} | |
[Test] | |
public void Get_WithManualAndDefaultParameters_ManuelOverridesDefault() | |
{ | |
// Arrange | |
Container.Transient<IA, A>(); | |
var wrongA = new A(); | |
var a = new A(); | |
Container.Transient<IJ, J>(new Hashtable { { "a", wrongA }, { "manual", "Injected!" } }); | |
// Act | |
var actual = Container.Get<IJ>(new Hashtable { { "a", a } }); | |
// Assert | |
Assert.That(actual, Is.TypeOf<J>()); | |
Assert.That(( (J)actual ).A, Is.SameAs(a)); | |
} | |
private static void AssertThrowsWithRootCause(Action action, ComponentResolutionError rootCause) | |
{ | |
Assert.That(() => action(), | |
Throws.InstanceOf<ComponentResolutionException>() | |
.With.Property("RootCause").EqualTo(rootCause)); | |
} | |
} | |
#region Components | |
public class A : IA { } | |
public interface IA { } | |
public interface IB { } | |
public class B : IB | |
{ | |
public B(IA a) { A = a; } | |
public IA A { get; private set; } | |
} | |
public interface IC { } | |
public class C : IC | |
{ | |
public C(IA a1, IA a2) { A1 = a1; A2 = a2; } | |
public IA A1 { get; private set; } | |
public IA A2 { get; private set; } | |
} | |
public interface ID { } | |
public class D : ID | |
{ | |
public D(IB b, IC c) { B = b; C = c; } | |
public IB B { get; private set; } | |
public IC C { get; private set; } | |
} | |
public interface IE { } | |
public class E : IE { public E(IE e) { } } | |
public interface IF { } | |
public class F : IF { public F(IG g) { } } | |
public interface IG { } | |
public class G : IG { public G(IH h) { } } | |
public interface IH { } | |
public class H : IH { public H(IF f) { } } | |
public interface IJ { } | |
public class J : IJ | |
{ | |
public J(IA a, string manual) { A = a; Manual = manual; } | |
public IA A { get; private set; } | |
public string Manual { get; private set; } | |
} | |
#endregion | |
} |
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
// Release under MIT license Copyright (c) 2011 Bryan Menard, http://www.bryblog.com/license.txt | |
using System; | |
using System.Collections; | |
using System.Diagnostics; | |
namespace Dioc | |
{ | |
/// <summary> | |
/// Represents a registration for a component | |
/// </summary> | |
public class ComponentRegistration | |
{ | |
/// <summary> | |
/// Gets the type of the component registered | |
/// </summary> | |
public Type Type { get; private set; } | |
/// <summary> | |
/// Gets whether the component is a singleton or not | |
/// </summary> | |
public bool Singleton { get; private set; } | |
/// <summary> | |
/// Gets the instance | |
/// </summary> | |
public object Instance { get; private set; } | |
/// <summary> | |
/// Gets the factory method to use in order to create the instance | |
/// </summary> | |
public Func<object> FactoryMethod { get; private set; } | |
/// <summary> | |
/// Gets the parameters to inject manually | |
/// </summary> | |
public Hashtable Parameters { get; private set; } | |
/// <summary> | |
/// Private constructor. | |
/// </summary> | |
private ComponentRegistration() { } | |
/// <summary> | |
/// Creates registration for a singleton instance, created only once using dependency injection | |
/// </summary> | |
/// <param name="type">The type registered</param> | |
/// <param name="parameters">The parameters to inject manually</param> | |
/// <returns>The registration</returns> | |
public static ComponentRegistration CreateSingleton(Type type, Hashtable parameters = null) | |
{ | |
return new ComponentRegistration { Type = type, Singleton = true, Parameters = parameters }; | |
} | |
/// <summary> | |
/// Creates a registration for a singleton instance, created using the provided factory method | |
/// </summary> | |
/// <param name="type">The type registered</param> | |
/// <param name="factoryMethod">The factory method used to create instances</param> | |
/// <param name="parameters">The parameters to inject manually</param> | |
/// <returns>The registration</returns> | |
public static ComponentRegistration CreateSingleton(Type type, Func<object> factoryMethod, Hashtable parameters = null) | |
{ | |
return new ComponentRegistration { Type = type, FactoryMethod = factoryMethod, Singleton = true, Parameters = parameters }; | |
} | |
/// <summary> | |
/// Creates a registration for transient instances, created every time its needed using dependency injection | |
/// </summary> | |
/// <param name="type">The type registered</param> | |
/// <param name="parameters">The parameters to inject manually</param> | |
/// <returns>The registration</returns> | |
public static ComponentRegistration CreateTransient(Type type, Hashtable parameters = null) | |
{ | |
return new ComponentRegistration { Type = type, Parameters = parameters }; | |
} | |
/// <summary> | |
/// Creates a registration for transient instances, created using the provided factory method | |
/// </summary> | |
/// <param name="type">The type registered</param> | |
/// <param name="factoryMethod">The factory method used to create instances</param> | |
/// <param name="parameters">The parameters to inject manually</param> | |
/// <returns>The registration</returns> | |
public static ComponentRegistration CreateTransient(Type type, Func<object> factoryMethod, Hashtable parameters = null) | |
{ | |
return new ComponentRegistration { Type = type, FactoryMethod = factoryMethod, Parameters = parameters }; | |
} | |
/// <summary> | |
/// Creates a registration for a instance, provided before-hand | |
/// </summary> | |
/// <param name="type">The type registered</param> | |
/// <param name="instance">The instance</param> | |
/// <returns>The registration</returns> | |
public static ComponentRegistration CreateInstance(Type type, object instance) | |
{ | |
Debug.Assert(type.IsAssignableFrom(instance.GetType())); | |
return new ComponentRegistration { Type = type, Instance = instance }; | |
} | |
} | |
} |
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
// Release under MIT license Copyright (c) 2011 Bryan Menard, http://www.bryblog.com/license.txt | |
using System; | |
using System.Text; | |
namespace Dioc | |
{ | |
public enum ComponentResolutionError | |
{ | |
None = 0, | |
AlreadyRegistered, | |
NotRegistered, | |
ConstructorNotFound, | |
DependencyResolution, | |
CircularDependency | |
} | |
/// <summary> | |
/// Represents an exception with component resolution. | |
/// </summary> | |
[Serializable] | |
public class ComponentResolutionException : ApplicationException | |
{ | |
public ComponentResolutionError Error { get; private set; } | |
public ComponentResolutionError RootCause { get; private set; } | |
public ComponentResolutionException(string message, ComponentResolutionError error) | |
: base(message) | |
{ | |
Error = RootCause = error; | |
} | |
public ComponentResolutionException(string message, Exception inner, ComponentResolutionError error) | |
: base(FormatMessage(message, inner), inner) | |
{ | |
Error = error; | |
var componentException = inner as ComponentResolutionException; | |
if (componentException != null) | |
{ | |
RootCause = componentException.RootCause; | |
} | |
} | |
private static string FormatMessage(string message, Exception inner) | |
{ | |
return FormatMessage(message, inner.Message ?? string.Empty); | |
} | |
public static string FormatMessage(string message, string innerMessage) | |
{ | |
var sb = new StringBuilder(); | |
sb.AppendLine(message); | |
sb.Append((innerMessage ?? string.Empty).Replace(Environment.NewLine, Environment.NewLine + ".. ")); | |
return sb.ToString(); | |
} | |
public static ComponentResolutionException NotRegistered(Type type) | |
{ | |
throw new ComponentResolutionException( | |
string.Format("Unable to resolve type {0}. The component was not registered.", type), | |
ComponentResolutionError.NotRegistered); | |
} | |
public static ComponentResolutionException AlreadyRegistered(Type type) | |
{ | |
throw new ComponentResolutionException( | |
string.Format("The type {0} was already registered.", type), | |
ComponentResolutionError.AlreadyRegistered); | |
} | |
public static ComponentResolutionException ConstructorNotFound(Type type) | |
{ | |
throw new ComponentResolutionException( | |
string.Format("Unable to find a suitable constructor for type {0}.", type), | |
ComponentResolutionError.ConstructorNotFound); | |
} | |
public static ComponentResolutionException DependencyResolution(Type type, Exception innerException) | |
{ | |
throw new ComponentResolutionException( | |
string.Format("Unable to resolve dependencies for {0}.", type), | |
innerException, | |
ComponentResolutionError.DependencyResolution); | |
} | |
public static ComponentResolutionException CircularDependency(Type type, Type dependency) | |
{ | |
return new ComponentResolutionException( | |
FormatMessage(string.Format("A circular dependency was detected within {0}.", type), dependency.ToString()), | |
ComponentResolutionError.CircularDependency); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment