using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace Tango.Core.DI
{
///
/// Represents the default Tango IOC container.
///
///
public class TangoIOC : ExtendedObject, ITangoIOC
{
private class RegisteredType
{
public Type InterfaceType { get; set; }
public Type ImplementationType { get; set; }
public Object Instance { get; set; }
public RegisteredType(Type interfaceType, Type implementationType, Object instance)
{
InterfaceType = interfaceType;
ImplementationType = implementationType;
Instance = instance;
}
}
private static TangoIOC _default;
///
/// Gets the default Tango IOC container instance.
///
public static TangoIOC Default
{
get
{
if (_default == null)
{
_default = new TangoIOC();
}
return _default;
}
}
private Dictionary _registeredTypes;
private List>> _waitingRetrivals;
///
/// Gets or sets a value indicating whether to throw an exception when a type is requested but not registered.
///
public bool ThrowOnRequestedTypeNotFound { get; set; } = true;
///
/// Initializes a new instance of the class.
///
public TangoIOC()
{
_registeredTypes = new Dictionary();
_waitingRetrivals = new List>>();
}
///
/// Registers the specified type.
///
///
public void Register() where T : class
{
RegisterInternal(typeof(T), typeof(T), null);
}
///
/// Registers the specified instance type and instance.
///
///
/// The instance.
public void Register(T instance) where T : class
{
RegisterInternal(typeof(T), instance.GetType(), instance);
}
///
/// Registers the specified type.
///
/// The type.
public void Register(Type type)
{
RegisterInternal(type, type, null);
}
///
/// Registers the specified type and implementation type.
///
/// The type.
/// The implementation.
public void Register(Type type, Type implementation)
{
RegisterInternal(type, implementation.GetType(), null);
}
///
/// Registers the specified type and instance.
///
/// The type.
/// The instance.
public void Register(Type type, Object instance)
{
RegisterInternal(type, instance.GetType(), instance);
}
///
/// Registers this instance.
///
/// The type of the type.
/// The type of the implementation.
public void Register() where Implementation : class, Type
{
RegisterInternal(typeof(Type), typeof(Implementation), null);
}
///
/// Registers the specified type, implementation and implementation instance.
///
/// The type of the type.
/// The type of the implementation.
/// The instance.
public void Register(Implementation instance) where Implementation : class, Type
{
RegisterInternal(typeof(Type), typeof(Implementation), instance);
}
///
/// Unregisters the specified type.
///
///
public void Unregister()
{
Unregister(typeof(T));
}
///
/// Unregisters the specified type.
///
/// The type.
public virtual void Unregister(Type type)
{
_registeredTypes.Remove(type);
}
///
/// Gets the instance of type T.
///
///
///
public T GetInstance()
{
return (T)GetInstance(typeof(T));
}
///
/// Notifies the awaiting retrievals of a new instance available.
///
/// Type of the registered.
private void NotifyAwaitingRetrievals(RegisteredType registeredType)
{
var toNotify = _waitingRetrivals.Where(x => x.Item1 == registeredType.InterfaceType).ToList();
toNotify.ForEach(x => x.Item2(registeredType.Instance));
_waitingRetrivals.RemoveAll(x => toNotify.Contains(x));
}
///
/// Gets the instance by the specified type.
///
/// The type.
///
/// The type specified could not be located!
public virtual object GetInstance(Type type)
{
RegisteredType registeredType = null;
if (_registeredTypes.TryGetValue(type, out registeredType))
{
if (registeredType.Instance == null)
{
registeredType.Instance = CreateInstance(registeredType.ImplementationType);
NotifyAwaitingRetrievals(registeredType);
}
return registeredType.Instance;
}
else
{
//Try get by inherited..
registeredType = _registeredTypes.Select(x => x.Value).SingleOrDefault(x => type.IsAssignableFrom(x.InterfaceType));
if (registeredType != null)
{
if (registeredType.Instance == null)
{
registeredType.Instance = CreateInstance(registeredType.ImplementationType);
NotifyAwaitingRetrievals(registeredType);
}
return registeredType.Instance;
}
if (!DesignMode && ThrowOnRequestedTypeNotFound)
{
throw new InvalidOperationException(String.Format("Requested type '{0}' could not be found.", type.Name));
}
else
{
return null;
}
}
}
///
/// Executes the specified action when type T is available. if already available action will be executed immediately.
///
///
/// The callback.
///
public void GetInstanceWhenAvailable(Action callback)
{
GetInstanceWhenAvailable(typeof(T), (x) => callback((T)x));
}
///
/// Executes the specified action when type T is available. if already available action will be executed immediately.
///
/// The callback.
///
public virtual void GetInstanceWhenAvailable(Type type, Action