Radarr/src/NzbDrone.Common/TinyIoC.cs

3777 lines
160 KiB
C#

//===============================================================================
// TinyIoC
//
// An easy to use, hassle free, Inversion of Control Container for small projects
// and beginners alike.
//
// https://github.com/grumpydev/TinyIoC
//===============================================================================
// Copyright © Steven Robbins. All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===============================================================================
#region Preprocessor Directives
// Uncomment this line if you want the container to automatically
// register the TinyMessenger messenger/event aggregator
//#define TINYMESSENGER
// Preprocessor directives for enabling/disabling functionality
// depending on platform features. If the platform has an appropriate
// #DEFINE then these should be set automatically below.
#define EXPRESSIONS // Platform supports System.Linq.Expressions
#define COMPILED_EXPRESSIONS // Platform supports compiling expressions
#define APPDOMAIN_GETASSEMBLIES // Platform supports getting all assemblies from the AppDomain object
#define UNBOUND_GENERICS_GETCONSTRUCTORS // Platform supports GetConstructors on unbound generic types
#define GETPARAMETERS_OPEN_GENERICS // Platform supports GetParameters on open generics
#define RESOLVE_OPEN_GENERICS // Platform supports resolving open generics
#define READER_WRITER_LOCK_SLIM // Platform supports ReaderWriterLockSlim
//// NETFX_CORE
//#if NETFX_CORE
//#endif
// CompactFramework / Windows Phone 7
// By default does not support System.Linq.Expressions.
// AppDomain object does not support enumerating all assemblies in the app domain.
#if PocketPC || WINDOWS_PHONE
#undef EXPRESSIONS
#undef COMPILED_EXPRESSIONS
#undef APPDOMAIN_GETASSEMBLIES
#undef UNBOUND_GENERICS_GETCONSTRUCTORS
#endif
// PocketPC has a bizarre limitation on enumerating parameters on unbound generic methods.
// We need to use a slower workaround in that case.
#if PocketPC
#undef GETPARAMETERS_OPEN_GENERICS
#undef RESOLVE_OPEN_GENERICS
#undef READER_WRITER_LOCK_SLIM
#endif
#if SILVERLIGHT
#undef APPDOMAIN_GETASSEMBLIES
#endif
#if NETFX_CORE
#undef APPDOMAIN_GETASSEMBLIES
#undef RESOLVE_OPEN_GENERICS
#endif
#if COMPILED_EXPRESSIONS
#define USE_OBJECT_CONSTRUCTOR
#endif
#endregion
namespace TinyIoC
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
#if EXPRESSIONS
using System.Linq.Expressions;
using NLog;
using System.Threading;
#endif
#if NETFX_CORE
using System.Threading.Tasks;
using Windows.Storage.Search;
using Windows.Storage;
using Windows.UI.Xaml.Shapes;
#endif
#region SafeDictionary
#if READER_WRITER_LOCK_SLIM
public class SafeDictionary<TKey, TValue> : IDisposable
{
private readonly ReaderWriterLockSlim _padlock = new ReaderWriterLockSlim();
private readonly Dictionary<TKey, TValue> _Dictionary = new Dictionary<TKey, TValue>();
public TValue this[TKey key]
{
set
{
_padlock.EnterWriteLock();
try
{
TValue current;
if (_Dictionary.TryGetValue(key, out current))
{
var disposable = current as IDisposable;
if (disposable != null)
disposable.Dispose();
}
_Dictionary[key] = value;
}
finally
{
_padlock.ExitWriteLock();
}
}
}
public bool TryGetValue(TKey key, out TValue value)
{
_padlock.EnterReadLock();
try
{
return _Dictionary.TryGetValue(key, out value);
}
finally
{
_padlock.ExitReadLock();
}
}
public bool Remove(TKey key)
{
_padlock.EnterWriteLock();
try
{
return _Dictionary.Remove(key);
}
finally
{
_padlock.ExitWriteLock();
}
}
public void Clear()
{
_padlock.EnterWriteLock();
try
{
_Dictionary.Clear();
}
finally
{
_padlock.ExitWriteLock();
}
}
public IEnumerable<TKey> Keys
{
get
{
_padlock.EnterReadLock();
try
{
return new List<TKey>(_Dictionary.Keys);
}
finally
{
_padlock.ExitReadLock();
}
}
}
#region IDisposable Members
public void Dispose()
{
_padlock.EnterWriteLock();
try
{
var disposableItems = from item in _Dictionary.Values
where item is IDisposable
select item as IDisposable;
foreach (var item in disposableItems)
{
item.Dispose();
}
}
finally
{
_padlock.ExitWriteLock();
}
GC.SuppressFinalize(this);
}
#endregion
}
#else
public class SafeDictionary<TKey, TValue> : IDisposable
{
private readonly object _Padlock = new object();
private readonly Dictionary<TKey, TValue> _Dictionary = new Dictionary<TKey, TValue>();
public TValue this[TKey key]
{
set
{
lock (_Padlock)
{
TValue current;
if (_Dictionary.TryGetValue(key, out current))
{
var disposable = current as IDisposable;
if (disposable != null)
disposable.Dispose();
}
_Dictionary[key] = value;
}
}
}
public bool TryGetValue(TKey key, out TValue value)
{
lock (_Padlock)
{
return _Dictionary.TryGetValue(key, out value);
}
}
public bool Remove(TKey key)
{
lock (_Padlock)
{
return _Dictionary.Remove(key);
}
}
public void Clear()
{
lock (_Padlock)
{
_Dictionary.Clear();
}
}
public IEnumerable<TKey> Keys
{
get
{
return _Dictionary.Keys;
}
}
#region IDisposable Members
public void Dispose()
{
lock (_Padlock)
{
var disposableItems = from item in _Dictionary.Values
where item is IDisposable
select item as IDisposable;
foreach (var item in disposableItems)
{
item.Dispose();
}
}
GC.SuppressFinalize(this);
}
#endregion
}
#endif
#endregion
#region Extensions
public static class AssemblyExtensions
{
public static Type[] SafeGetTypes(this Assembly assembly)
{
Type[] assemblies;
try
{
assemblies = assembly.GetTypes();
}
catch (System.IO.FileNotFoundException)
{
assemblies = new Type[] { };
}
catch (NotSupportedException)
{
assemblies = new Type[] { };
}
#if !NETFX_CORE
catch (ReflectionTypeLoadException e)
{
assemblies = e.Types.Where(t => t != null).ToArray();
}
#endif
return assemblies;
}
}
public static class TypeExtensions
{
private static SafeDictionary<GenericMethodCacheKey, MethodInfo> _genericMethodCache;
static TypeExtensions()
{
_genericMethodCache = new SafeDictionary<GenericMethodCacheKey, MethodInfo>();
}
//#if NETFX_CORE
// /// <summary>
// /// Gets a generic method from a type given the method name, generic types and parameter types
// /// </summary>
// /// <param name="sourceType">Source type</param>
// /// <param name="methodName">Name of the method</param>
// /// <param name="genericTypes">Generic types to use to make the method generic</param>
// /// <param name="parameterTypes">Method parameters</param>
// /// <returns>MethodInfo or null if no matches found</returns>
// /// <exception cref="System.Reflection.AmbiguousMatchException"/>
// /// <exception cref="System.ArgumentException"/>
// public static MethodInfo GetGenericMethod(this Type sourceType, string methodName, Type[] genericTypes, Type[] parameterTypes)
// {
// MethodInfo method;
// var cacheKey = new GenericMethodCacheKey(sourceType, methodName, genericTypes, parameterTypes);
// // Shouldn't need any additional locking
// // we don't care if we do the method info generation
// // more than once before it gets cached.
// if (!_genericMethodCache.TryGetValue(cacheKey, out method))
// {
// method = GetMethod(sourceType, methodName, genericTypes, parameterTypes);
// _genericMethodCache[cacheKey] = method;
// }
// return method;
// }
//#else
/// <summary>
/// Gets a generic method from a type given the method name, binding flags, generic types and parameter types
/// </summary>
/// <param name="sourceType">Source type</param>
/// <param name="bindingFlags">Binding flags</param>
/// <param name="methodName">Name of the method</param>
/// <param name="genericTypes">Generic types to use to make the method generic</param>
/// <param name="parameterTypes">Method parameters</param>
/// <returns>MethodInfo or null if no matches found</returns>
/// <exception cref="System.Reflection.AmbiguousMatchException"/>
/// <exception cref="System.ArgumentException"/>
public static MethodInfo GetGenericMethod(this Type sourceType, BindingFlags bindingFlags, string methodName, Type[] genericTypes, Type[] parameterTypes)
{
MethodInfo method;
var cacheKey = new GenericMethodCacheKey(sourceType, methodName, genericTypes, parameterTypes);
// Shouldn't need any additional locking
// we don't care if we do the method info generation
// more than once before it gets cached.
if (!_genericMethodCache.TryGetValue(cacheKey, out method))
{
method = GetMethod(sourceType, bindingFlags, methodName, genericTypes, parameterTypes);
_genericMethodCache[cacheKey] = method;
}
return method;
}
//#endif
#if NETFX_CORE
private static MethodInfo GetMethod(Type sourceType, BindingFlags flags, string methodName, Type[] genericTypes, Type[] parameterTypes)
{
var methods =
sourceType.GetMethods(flags).Where(
mi => string.Equals(methodName, mi.Name, StringComparison.Ordinal)).Where(
mi => mi.ContainsGenericParameters).Where(mi => mi.GetGenericArguments().Length == genericTypes.Length).
Where(mi => mi.GetParameters().Length == parameterTypes.Length).Select(
mi => mi.MakeGenericMethod(genericTypes)).Where(
mi => mi.GetParameters().Select(pi => pi.ParameterType).SequenceEqual(parameterTypes)).ToList();
if (methods.Count > 1)
{
throw new AmbiguousMatchException();
}
return methods.FirstOrDefault();
}
#else
private static MethodInfo GetMethod(Type sourceType, BindingFlags bindingFlags, string methodName, Type[] genericTypes, Type[] parameterTypes)
{
#if GETPARAMETERS_OPEN_GENERICS
var methods =
sourceType.GetMethods(bindingFlags).Where(
mi => string.Equals(methodName, mi.Name, StringComparison.Ordinal)).Where(
mi => mi.ContainsGenericParameters).Where(mi => mi.GetGenericArguments().Length == genericTypes.Length).
Where(mi => mi.GetParameters().Length == parameterTypes.Length).Select(
mi => mi.MakeGenericMethod(genericTypes)).Where(
mi => mi.GetParameters().Select(pi => pi.ParameterType).SequenceEqual(parameterTypes)).ToList();
#else
var validMethods = from method in sourceType.GetMethods(bindingFlags)
where method.Name == methodName
where method.IsGenericMethod
where method.GetGenericArguments().Length == genericTypes.Length
let genericMethod = method.MakeGenericMethod(genericTypes)
where genericMethod.GetParameters().Count() == parameterTypes.Length
where genericMethod.GetParameters().Select(pi => pi.ParameterType).SequenceEqual(parameterTypes)
select genericMethod;
var methods = validMethods.ToList();
#endif
if (methods.Count > 1)
{
throw new AmbiguousMatchException();
}
return methods.FirstOrDefault();
}
#endif
private sealed class GenericMethodCacheKey
{
private readonly Type _sourceType;
private readonly string _methodName;
private readonly Type[] _genericTypes;
private readonly Type[] _parameterTypes;
private readonly int _hashCode;
public GenericMethodCacheKey(Type sourceType, string methodName, Type[] genericTypes, Type[] parameterTypes)
{
_sourceType = sourceType;
_methodName = methodName;
_genericTypes = genericTypes;
_parameterTypes = parameterTypes;
_hashCode = GenerateHashCode();
}
public override bool Equals(object obj)
{
var cacheKey = obj as GenericMethodCacheKey;
if (cacheKey == null)
return false;
if (_sourceType != cacheKey._sourceType)
return false;
if (!string.Equals(_methodName, cacheKey._methodName, StringComparison.Ordinal))
return false;
if (_genericTypes.Length != cacheKey._genericTypes.Length)
return false;
if (_parameterTypes.Length != cacheKey._parameterTypes.Length)
return false;
for (int i = 0; i < _genericTypes.Length; ++i)
{
if (_genericTypes[i] != cacheKey._genericTypes[i])
return false;
}
for (int i = 0; i < _parameterTypes.Length; ++i)
{
if (_parameterTypes[i] != cacheKey._parameterTypes[i])
return false;
}
return true;
}
public override int GetHashCode()
{
return _hashCode;
}
private int GenerateHashCode()
{
unchecked
{
var result = _sourceType.GetHashCode();
result = (result * 397) ^ _methodName.GetHashCode();
for (int i = 0; i < _genericTypes.Length; ++i)
{
result = (result * 397) ^ _genericTypes[i].GetHashCode();
}
for (int i = 0; i < _parameterTypes.Length; ++i)
{
result = (result * 397) ^ _parameterTypes[i].GetHashCode();
}
return result;
}
}
}
}
// @mbrit - 2012-05-22 - shim for ForEach call on List<T>...
#if NETFX_CORE
internal static class ListExtender
{
internal static void ForEach<T>(this List<T> list, Action<T> callback)
{
foreach (T obj in list)
callback(obj);
}
}
#endif
#endregion
#region TinyIoC Exception Types
public class TinyIoCResolutionException : Exception
{
private const string ERROR_TEXT = "Unable to resolve type: {0}";
public TinyIoCResolutionException(Type type)
: base(string.Format(ERROR_TEXT, type.FullName))
{
}
public TinyIoCResolutionException(Type type, Exception innerException)
: base(string.Format(ERROR_TEXT, type.FullName), innerException)
{
}
}
public class TinyIoCRegistrationTypeException : Exception
{
private const string REGISTER_ERROR_TEXT = "Cannot register type {0} - abstract classes or interfaces are not valid implementation types for {1}.";
public TinyIoCRegistrationTypeException(Type type, string factory)
: base(string.Format(REGISTER_ERROR_TEXT, type.FullName, factory))
{
}
public TinyIoCRegistrationTypeException(Type type, string factory, Exception innerException)
: base(string.Format(REGISTER_ERROR_TEXT, type.FullName, factory), innerException)
{
}
}
public class TinyIoCRegistrationException : Exception
{
private const string CONVERT_ERROR_TEXT = "Cannot convert current registration of {0} to {1}";
private const string GENERIC_CONSTRAINT_ERROR_TEXT = "Type {1} is not valid for a registration of type {0}";
public TinyIoCRegistrationException(Type type, string method)
: base(string.Format(CONVERT_ERROR_TEXT, type.FullName, method))
{
}
public TinyIoCRegistrationException(Type type, string method, Exception innerException)
: base(string.Format(CONVERT_ERROR_TEXT, type.FullName, method), innerException)
{
}
public TinyIoCRegistrationException(Type registerType, Type implementationType)
: base(string.Format(GENERIC_CONSTRAINT_ERROR_TEXT, registerType.FullName, implementationType.FullName))
{
}
public TinyIoCRegistrationException(Type registerType, Type implementationType, Exception innerException)
: base(string.Format(GENERIC_CONSTRAINT_ERROR_TEXT, registerType.FullName, implementationType.FullName), innerException)
{
}
}
public class TinyIoCWeakReferenceException : Exception
{
private const string ERROR_TEXT = "Unable to instantiate {0} - referenced object has been reclaimed";
public TinyIoCWeakReferenceException(Type type)
: base(string.Format(ERROR_TEXT, type.FullName))
{
}
public TinyIoCWeakReferenceException(Type type, Exception innerException)
: base(string.Format(ERROR_TEXT, type.FullName), innerException)
{
}
}
public class TinyIoCConstructorResolutionException : Exception
{
private const string ERROR_TEXT = "Unable to resolve constructor for {0} using provided Expression.";
public TinyIoCConstructorResolutionException(Type type)
: base(string.Format(ERROR_TEXT, type.FullName))
{
}
public TinyIoCConstructorResolutionException(Type type, Exception innerException)
: base(string.Format(ERROR_TEXT, type.FullName), innerException)
{
}
public TinyIoCConstructorResolutionException(string message, Exception innerException)
: base(message, innerException)
{
}
public TinyIoCConstructorResolutionException(string message)
: base(message)
{
}
}
public class TinyIoCAutoRegistrationException : Exception
{
private const string ERROR_TEXT = "Duplicate implementation of type {0} found ({1}).";
public TinyIoCAutoRegistrationException(Type registerType, IEnumerable<Type> types)
: base(string.Format(ERROR_TEXT, registerType, GetTypesString(types)))
{
}
public TinyIoCAutoRegistrationException(Type registerType, IEnumerable<Type> types, Exception innerException)
: base(string.Format(ERROR_TEXT, registerType, GetTypesString(types)), innerException)
{
}
private static string GetTypesString(IEnumerable<Type> types)
{
var typeNames = from type in types
select type.FullName;
return string.Join(",", typeNames.ToArray());
}
}
#endregion
#region Public Setup / Settings Classes
/// <summary>
/// Name/Value pairs for specifying "user" parameters when resolving
/// </summary>
public sealed class NamedParameterOverloads : Dictionary<string, object>
{
public static NamedParameterOverloads FromIDictionary(IDictionary<string, object> data)
{
return data as NamedParameterOverloads ?? new NamedParameterOverloads(data);
}
public NamedParameterOverloads()
{
}
public NamedParameterOverloads(IDictionary<string, object> data)
: base(data)
{
}
private static readonly NamedParameterOverloads _Default = new NamedParameterOverloads();
public static NamedParameterOverloads Default => _Default;
}
public enum UnregisteredResolutionActions
{
/// <summary>
/// Attempt to resolve type, even if the type isn't registered.
///
/// Registered types/options will always take precedence.
/// </summary>
AttemptResolve,
/// <summary>
/// Fail resolution if type not explicitly registered
/// </summary>
Fail,
/// <summary>
/// Attempt to resolve unregistered type if requested type is generic
/// and no registration exists for the specific generic parameters used.
///
/// Registered types/options will always take precedence.
/// </summary>
GenericsOnly
}
public enum NamedResolutionFailureActions
{
AttemptUnnamedResolution,
Fail
}
public enum DuplicateImplementationActions
{
RegisterSingle,
RegisterMultiple,
Fail
}
/// <summary>
/// Resolution settings
/// </summary>
public sealed class ResolveOptions
{
private static readonly ResolveOptions _Default = new ResolveOptions();
private static readonly ResolveOptions _FailUnregisteredAndNameNotFound = new ResolveOptions() { NamedResolutionFailureAction = NamedResolutionFailureActions.Fail, UnregisteredResolutionAction = UnregisteredResolutionActions.Fail };
private static readonly ResolveOptions _FailUnregisteredOnly = new ResolveOptions() { NamedResolutionFailureAction = NamedResolutionFailureActions.AttemptUnnamedResolution, UnregisteredResolutionAction = UnregisteredResolutionActions.Fail };
private static readonly ResolveOptions _FailNameNotFoundOnly = new ResolveOptions() { NamedResolutionFailureAction = NamedResolutionFailureActions.Fail, UnregisteredResolutionAction = UnregisteredResolutionActions.AttemptResolve };
private UnregisteredResolutionActions _UnregisteredResolutionAction = UnregisteredResolutionActions.AttemptResolve;
public UnregisteredResolutionActions UnregisteredResolutionAction
{
get { return _UnregisteredResolutionAction; }
set { _UnregisteredResolutionAction = value; }
}
private NamedResolutionFailureActions _NamedResolutionFailureAction = NamedResolutionFailureActions.Fail;
public NamedResolutionFailureActions NamedResolutionFailureAction
{
get { return _NamedResolutionFailureAction; }
set { _NamedResolutionFailureAction = value; }
}
/// <summary>
/// Gets the default options (attempt resolution of unregistered types, fail on named resolution if name not found)
/// </summary>
public static ResolveOptions Default => _Default;
/// <summary>
/// Preconfigured option for attempting resolution of unregistered types and failing on named resolution if name not found
/// </summary>
public static ResolveOptions FailNameNotFoundOnly => _FailNameNotFoundOnly;
/// <summary>
/// Preconfigured option for failing on resolving unregistered types and on named resolution if name not found
/// </summary>
public static ResolveOptions FailUnregisteredAndNameNotFound => _FailUnregisteredAndNameNotFound;
/// <summary>
/// Preconfigured option for failing on resolving unregistered types, but attempting unnamed resolution if name not found
/// </summary>
public static ResolveOptions FailUnregisteredOnly => _FailUnregisteredOnly;
}
#endregion
public sealed partial class TinyIoCContainer : IDisposable
{
#region Fake NETFX_CORE Classes
#if NETFX_CORE
private sealed class MethodAccessException : Exception
{
}
private sealed class AppDomain
{
public static AppDomain CurrentDomain { get; private set; }
static AppDomain()
{
CurrentDomain = new AppDomain();
}
// @mbrit - 2012-05-30 - in WinRT, this should be done async...
public async Task<List<Assembly>> GetAssembliesAsync()
{
var folder = Windows.ApplicationModel.Package.Current.InstalledLocation;
List<Assembly> assemblies = new List<Assembly>();
var files = await folder.GetFilesAsync();
foreach (StorageFile file in files)
{
if (file.FileType == ".dll" || file.FileType == ".exe")
{
AssemblyName name = new AssemblyName() { Name = System.IO.Path.GetFileNameWithoutExtension(file.Name) };
try
{
var asm = Assembly.Load(name);
assemblies.Add(asm);
}
catch
{
// ignore exceptions here...
}
}
}
return assemblies;
}
}
#endif
#endregion
#region "Fluent" API
/// <summary>
/// Registration options for "fluent" API
/// </summary>
public sealed class RegisterOptions
{
private TinyIoCContainer _Container;
private TypeRegistration _Registration;
public RegisterOptions(TinyIoCContainer container, TypeRegistration registration)
{
_Container = container;
_Registration = registration;
}
/// <summary>
/// Make registration a singleton (single instance) if possible
/// </summary>
/// <returns>RegisterOptions</returns>
/// <exception cref="TinyIoCInstantiationTypeException"></exception>
public RegisterOptions AsSingleton()
{
var currentFactory = _Container.GetCurrentFactory(_Registration);
if (currentFactory == null)
throw new TinyIoCRegistrationException(_Registration.Type, "singleton");
return _Container.AddUpdateRegistration(_Registration, currentFactory.SingletonVariant);
}
/// <summary>
/// Make registration multi-instance if possible
/// </summary>
/// <returns>RegisterOptions</returns>
/// <exception cref="TinyIoCInstantiationTypeException"></exception>
public RegisterOptions AsMultiInstance()
{
var currentFactory = _Container.GetCurrentFactory(_Registration);
if (currentFactory == null)
throw new TinyIoCRegistrationException(_Registration.Type, "multi-instance");
return _Container.AddUpdateRegistration(_Registration, currentFactory.MultiInstanceVariant);
}
/// <summary>
/// Make registration hold a weak reference if possible
/// </summary>
/// <returns>RegisterOptions</returns>
/// <exception cref="TinyIoCInstantiationTypeException"></exception>
public RegisterOptions WithWeakReference()
{
var currentFactory = _Container.GetCurrentFactory(_Registration);
if (currentFactory == null)
throw new TinyIoCRegistrationException(_Registration.Type, "weak reference");
return _Container.AddUpdateRegistration(_Registration, currentFactory.WeakReferenceVariant);
}
/// <summary>
/// Make registration hold a strong reference if possible
/// </summary>
/// <returns>RegisterOptions</returns>
/// <exception cref="TinyIoCInstantiationTypeException"></exception>
public RegisterOptions WithStrongReference()
{
var currentFactory = _Container.GetCurrentFactory(_Registration);
if (currentFactory == null)
throw new TinyIoCRegistrationException(_Registration.Type, "strong reference");
return _Container.AddUpdateRegistration(_Registration, currentFactory.StrongReferenceVariant);
}
#if EXPRESSIONS
public RegisterOptions UsingConstructor<RegisterType>(Expression<Func<RegisterType>> constructor)
{
var lambda = constructor as LambdaExpression;
if (lambda == null)
throw new TinyIoCConstructorResolutionException(typeof(RegisterType));
var newExpression = lambda.Body as NewExpression;
if (newExpression == null)
throw new TinyIoCConstructorResolutionException(typeof(RegisterType));
var constructorInfo = newExpression.Constructor;
if (constructorInfo == null)
throw new TinyIoCConstructorResolutionException(typeof(RegisterType));
var currentFactory = _Container.GetCurrentFactory(_Registration);
if (currentFactory == null)
throw new TinyIoCConstructorResolutionException(typeof(RegisterType));
currentFactory.SetConstructor(constructorInfo);
return this;
}
#endif
/// <summary>
/// Switches to a custom lifetime manager factory if possible.
///
/// Usually used for RegisterOptions "To*" extension methods such as the ASP.Net per-request one.
/// </summary>
/// <param name="instance">RegisterOptions instance</param>
/// <param name="lifetimeProvider">Custom lifetime manager</param>
/// <param name="errorString">Error string to display if switch fails</param>
/// <returns>RegisterOptions</returns>
public static RegisterOptions ToCustomLifetimeManager(RegisterOptions instance, ITinyIoCObjectLifetimeProvider lifetimeProvider, string errorString)
{
if (instance == null)
throw new ArgumentNullException("instance", "instance is null.");
if (lifetimeProvider == null)
throw new ArgumentNullException("lifetimeProvider", "lifetimeProvider is null.");
if (string.IsNullOrEmpty(errorString))
throw new ArgumentException("errorString is null or empty.", "errorString");
var currentFactory = instance._Container.GetCurrentFactory(instance._Registration);
if (currentFactory == null)
throw new TinyIoCRegistrationException(instance._Registration.Type, errorString);
return instance._Container.AddUpdateRegistration(instance._Registration, currentFactory.GetCustomObjectLifetimeVariant(lifetimeProvider, errorString));
}
}
/// <summary>
/// Registration options for "fluent" API when registering multiple implementations
/// </summary>
public sealed class MultiRegisterOptions
{
private IEnumerable<RegisterOptions> _RegisterOptions;
/// <summary>
/// Initializes a new instance of the MultiRegisterOptions class.
/// </summary>
/// <param name="registerOptions">Registration options</param>
public MultiRegisterOptions(IEnumerable<RegisterOptions> registerOptions)
{
_RegisterOptions = registerOptions;
}
/// <summary>
/// Make registration a singleton (single instance) if possible
/// </summary>
/// <returns>RegisterOptions</returns>
/// <exception cref="TinyIoCInstantiationTypeException"></exception>
public MultiRegisterOptions AsSingleton()
{
_RegisterOptions = ExecuteOnAllRegisterOptions(ro => ro.AsSingleton());
return this;
}
/// <summary>
/// Make registration multi-instance if possible
/// </summary>
/// <returns>MultiRegisterOptions</returns>
/// <exception cref="TinyIoCInstantiationTypeException"></exception>
public MultiRegisterOptions AsMultiInstance()
{
_RegisterOptions = ExecuteOnAllRegisterOptions(ro => ro.AsMultiInstance());
return this;
}
private IEnumerable<RegisterOptions> ExecuteOnAllRegisterOptions(Func<RegisterOptions, RegisterOptions> action)
{
var newRegisterOptions = new List<RegisterOptions>();
foreach (var registerOption in _RegisterOptions)
{
newRegisterOptions.Add(action(registerOption));
}
return newRegisterOptions;
}
}
#endregion
#region Public API
#region Child Containers
public TinyIoCContainer GetChildContainer()
{
return new TinyIoCContainer(this);
}
#endregion
#region Registration
/// <summary>
/// Attempt to automatically register all non-generic classes and interfaces in the current app domain.
///
/// If more than one class implements an interface then only one implementation will be registered
/// although no error will be thrown.
/// </summary>
public void AutoRegister()
{
#if APPDOMAIN_GETASSEMBLIES
AutoRegisterInternal(AppDomain.CurrentDomain.GetAssemblies().Where(a => !IsIgnoredAssembly(a)), DuplicateImplementationActions.RegisterSingle, null);
#else
AutoRegisterInternal(new Assembly[] {this.GetType().Assembly()}, true, null);
#endif
}
/// <summary>
/// Attempt to automatically register all non-generic classes and interfaces in the current app domain.
/// Types will only be registered if they pass the supplied registration predicate.
///
/// If more than one class implements an interface then only one implementation will be registered
/// although no error will be thrown.
/// </summary>
/// <param name="registrationPredicate">Predicate to determine if a particular type should be registered</param>
public void AutoRegister(Func<Type, bool> registrationPredicate)
{
#if APPDOMAIN_GETASSEMBLIES
AutoRegisterInternal(AppDomain.CurrentDomain.GetAssemblies().Where(a => !IsIgnoredAssembly(a)), DuplicateImplementationActions.RegisterSingle, registrationPredicate);
#else
AutoRegisterInternal(new Assembly[] { this.GetType().Assembly()}, true, registrationPredicate);
#endif
}
/// <summary>
/// Attempt to automatically register all non-generic classes and interfaces in the current app domain.
/// </summary>
/// <param name="duplicateAction">What action to take when encountering duplicate implementations of an interface/base class.</param>
/// <exception cref="TinyIoCAutoRegistrationException"/>
public void AutoRegister(DuplicateImplementationActions duplicateAction)
{
#if APPDOMAIN_GETASSEMBLIES
AutoRegisterInternal(AppDomain.CurrentDomain.GetAssemblies().Where(a => !IsIgnoredAssembly(a)), duplicateAction, null);
#else
AutoRegisterInternal(new Assembly[] { this.GetType().Assembly() }, ignoreDuplicateImplementations, null);
#endif
}
/// <summary>
/// Attempt to automatically register all non-generic classes and interfaces in the current app domain.
/// Types will only be registered if they pass the supplied registration predicate.
/// </summary>
/// <param name="duplicateAction">What action to take when encountering duplicate implementations of an interface/base class.</param>
/// <param name="registrationPredicate">Predicate to determine if a particular type should be registered</param>
/// <exception cref="TinyIoCAutoRegistrationException"/>
public void AutoRegister(DuplicateImplementationActions duplicateAction, Func<Type, bool> registrationPredicate)
{
#if APPDOMAIN_GETASSEMBLIES
AutoRegisterInternal(AppDomain.CurrentDomain.GetAssemblies().Where(a => !IsIgnoredAssembly(a)), duplicateAction, registrationPredicate);
#else
AutoRegisterInternal(new Assembly[] { this.GetType().Assembly() }, ignoreDuplicateImplementations, registrationPredicate);
#endif
}
/// <summary>
/// Attempt to automatically register all non-generic classes and interfaces in the specified assemblies
///
/// If more than one class implements an interface then only one implementation will be registered
/// although no error will be thrown.
/// </summary>
/// <param name="assemblies">Assemblies to process</param>
public void AutoRegister(IEnumerable<Assembly> assemblies)
{
AutoRegisterInternal(assemblies, DuplicateImplementationActions.RegisterSingle, null);
}
/// <summary>
/// Attempt to automatically register all non-generic classes and interfaces in the specified assemblies
/// Types will only be registered if they pass the supplied registration predicate.
///
/// If more than one class implements an interface then only one implementation will be registered
/// although no error will be thrown.
/// </summary>
/// <param name="assemblies">Assemblies to process</param>
/// <param name="registrationPredicate">Predicate to determine if a particular type should be registered</param>
public void AutoRegister(IEnumerable<Assembly> assemblies, Func<Type, bool> registrationPredicate)
{
AutoRegisterInternal(assemblies, DuplicateImplementationActions.RegisterSingle, registrationPredicate);
}
/// <summary>
/// Attempt to automatically register all non-generic classes and interfaces in the specified assemblies
/// </summary>
/// <param name="assemblies">Assemblies to process</param>
/// <param name="duplicateAction">What action to take when encountering duplicate implementations of an interface/base class.</param>
/// <exception cref="TinyIoCAutoRegistrationException"/>
public void AutoRegister(IEnumerable<Assembly> assemblies, DuplicateImplementationActions duplicateAction)
{
AutoRegisterInternal(assemblies, duplicateAction, null);
}
/// <summary>
/// Attempt to automatically register all non-generic classes and interfaces in the specified assemblies
/// Types will only be registered if they pass the supplied registration predicate.
/// </summary>
/// <param name="assemblies">Assemblies to process</param>
/// <param name="duplicateAction">What action to take when encountering duplicate implementations of an interface/base class.</param>
/// <param name="registrationPredicate">Predicate to determine if a particular type should be registered</param>
/// <exception cref="TinyIoCAutoRegistrationException"/>
public void AutoRegister(IEnumerable<Assembly> assemblies, DuplicateImplementationActions duplicateAction, Func<Type, bool> registrationPredicate)
{
AutoRegisterInternal(assemblies, duplicateAction, registrationPredicate);
}
/// <summary>
/// Creates/replaces a container class registration with default options.
/// </summary>
/// <param name="registerType">Type to register</param>
/// <returns>RegisterOptions for fluent API</returns>
public RegisterOptions Register(Type registerType)
{
return RegisterInternal(registerType, string.Empty, GetDefaultObjectFactory(registerType, registerType));
}
/// <summary>
/// Creates/replaces a named container class registration with default options.
/// </summary>
/// <param name="registerType">Type to register</param>
/// <param name="name">Name of registration</param>
/// <returns>RegisterOptions for fluent API</returns>
public RegisterOptions Register(Type registerType, string name)
{
return RegisterInternal(registerType, name, GetDefaultObjectFactory(registerType, registerType));
}
/// <summary>
/// Creates/replaces a container class registration with a given implementation and default options.
/// </summary>
/// <param name="registerType">Type to register</param>
/// <param name="registerImplementation">Type to instantiate that implements RegisterType</param>
/// <returns>RegisterOptions for fluent API</returns>
public RegisterOptions Register(Type registerType, Type registerImplementation)
{
return this.RegisterInternal(registerType, string.Empty, GetDefaultObjectFactory(registerType, registerImplementation));
}
/// <summary>
/// Creates/replaces a named container class registration with a given implementation and default options.
/// </summary>
/// <param name="registerType">Type to register</param>
/// <param name="registerImplementation">Type to instantiate that implements RegisterType</param>
/// <param name="name">Name of registration</param>
/// <returns>RegisterOptions for fluent API</returns>
public RegisterOptions Register(Type registerType, Type registerImplementation, string name)
{
return this.RegisterInternal(registerType, name, GetDefaultObjectFactory(registerType, registerImplementation));
}
/// <summary>
/// Creates/replaces a container class registration with a specific, strong referenced, instance.
/// </summary>
/// <param name="registerType">Type to register</param>
/// <param name="instance">Instance of RegisterType to register</param>
/// <returns>RegisterOptions for fluent API</returns>
public RegisterOptions Register(Type registerType, object instance)
{
return RegisterInternal(registerType, string.Empty, new InstanceFactory(registerType, registerType, instance));
}
/// <summary>
/// Creates/replaces a named container class registration with a specific, strong referenced, instance.
/// </summary>
/// <param name="registerType">Type to register</param>
/// <param name="instance">Instance of RegisterType to register</param>
/// <param name="name">Name of registration</param>
/// <returns>RegisterOptions for fluent API</returns>
public RegisterOptions Register(Type registerType, object instance, string name)
{
return RegisterInternal(registerType, name, new InstanceFactory(registerType, registerType, instance));
}
/// <summary>
/// Creates/replaces a container class registration with a specific, strong referenced, instance.
/// </summary>
/// <param name="registerType">Type to register</param>
/// <param name="registerImplementation">Type of instance to register that implements RegisterType</param>
/// <param name="instance">Instance of RegisterImplementation to register</param>
/// <returns>RegisterOptions for fluent API</returns>
public RegisterOptions Register(Type registerType, Type registerImplementation, object instance)
{
return RegisterInternal(registerType, string.Empty, new InstanceFactory(registerType, registerImplementation, instance));
}
/// <summary>
/// Creates/replaces a named container class registration with a specific, strong referenced, instance.
/// </summary>
/// <param name="registerType">Type to register</param>
/// <param name="registerImplementation">Type of instance to register that implements RegisterType</param>
/// <param name="instance">Instance of RegisterImplementation to register</param>
/// <param name="name">Name of registration</param>
/// <returns>RegisterOptions for fluent API</returns>
public RegisterOptions Register(Type registerType, Type registerImplementation, object instance, string name)
{
return RegisterInternal(registerType, name, new InstanceFactory(registerType, registerImplementation, instance));
}
/// <summary>
/// Creates/replaces a container class registration with a user specified factory
/// </summary>
/// <param name="registerType">Type to register</param>
/// <param name="factory">Factory/lambda that returns an instance of RegisterType</param>
/// <returns>RegisterOptions for fluent API</returns>
public RegisterOptions Register(Type registerType, Func<TinyIoCContainer, NamedParameterOverloads, object> factory)
{
return RegisterInternal(registerType, string.Empty, new DelegateFactory(registerType, factory));
}
/// <summary>
/// Creates/replaces a container class registration with a user specified factory
/// </summary>
/// <param name="registerType">Type to register</param>
/// <param name="factory">Factory/lambda that returns an instance of RegisterType</param>
/// <param name="name">Name of registation</param>
/// <returns>RegisterOptions for fluent API</returns>
public RegisterOptions Register(Type registerType, Func<TinyIoCContainer, NamedParameterOverloads, object> factory, string name)
{
return RegisterInternal(registerType, name, new DelegateFactory(registerType, factory));
}
/// <summary>
/// Creates/replaces a container class registration with default options.
/// </summary>
/// <typeparam name="RegisterImplementation">Type to register</typeparam>
/// <returns>RegisterOptions for fluent API</returns>
public RegisterOptions Register<RegisterType>()
where RegisterType : class
{
return this.Register(typeof(RegisterType));
}
/// <summary>
/// Creates/replaces a named container class registration with default options.
/// </summary>
/// <typeparam name="RegisterImplementation">Type to register</typeparam>
/// <param name="name">Name of registration</param>
/// <returns>RegisterOptions for fluent API</returns>
public RegisterOptions Register<RegisterType>(string name)
where RegisterType : class
{
return this.Register(typeof(RegisterType), name);
}
/// <summary>
/// Creates/replaces a container class registration with a given implementation and default options.
/// </summary>
/// <typeparam name="RegisterType">Type to register</typeparam>
/// <typeparam name="RegisterImplementation">Type to instantiate that implements RegisterType</typeparam>
/// <returns>RegisterOptions for fluent API</returns>
public RegisterOptions Register<RegisterType, RegisterImplementation>()
where RegisterType : class
where RegisterImplementation : class, RegisterType
{
return this.Register(typeof(RegisterType), typeof(RegisterImplementation));
}
/// <summary>
/// Creates/replaces a named container class registration with a given implementation and default options.
/// </summary>
/// <typeparam name="RegisterType">Type to register</typeparam>
/// <typeparam name="RegisterImplementation">Type to instantiate that implements RegisterType</typeparam>
/// <param name="name">Name of registration</param>
/// <returns>RegisterOptions for fluent API</returns>
public RegisterOptions Register<RegisterType, RegisterImplementation>(string name)
where RegisterType : class
where RegisterImplementation : class, RegisterType
{
return this.Register(typeof(RegisterType), typeof(RegisterImplementation), name);
}
/// <summary>
/// Creates/replaces a container class registration with a specific, strong referenced, instance.
/// </summary>
/// <typeparam name="RegisterType">Type to register</typeparam>
/// <param name="instance">Instance of RegisterType to register</param>
/// <returns>RegisterOptions for fluent API</returns>
public RegisterOptions Register<RegisterType>(RegisterType instance)
where RegisterType : class
{
return this.Register(typeof(RegisterType), instance);
}
/// <summary>
/// Creates/replaces a named container class registration with a specific, strong referenced, instance.
/// </summary>
/// <typeparam name="RegisterType">Type to register</typeparam>
/// <param name="instance">Instance of RegisterType to register</param>
/// <param name="name">Name of registration</param>
/// <returns>RegisterOptions for fluent API</returns>
public RegisterOptions Register<RegisterType>(RegisterType instance, string name)
where RegisterType : class
{
return this.Register(typeof(RegisterType), instance, name);
}
/// <summary>
/// Creates/replaces a container class registration with a specific, strong referenced, instance.
/// </summary>
/// <typeparam name="RegisterType">Type to register</typeparam>
/// <typeparam name="RegisterImplementation">Type of instance to register that implements RegisterType</typeparam>
/// <param name="instance">Instance of RegisterImplementation to register</param>
/// <returns>RegisterOptions for fluent API</returns>
public RegisterOptions Register<RegisterType, RegisterImplementation>(RegisterImplementation instance)
where RegisterType : class
where RegisterImplementation : class, RegisterType
{
return this.Register(typeof(RegisterType), typeof(RegisterImplementation), instance);
}
/// <summary>
/// Creates/replaces a named container class registration with a specific, strong referenced, instance.
/// </summary>
/// <typeparam name="RegisterType">Type to register</typeparam>
/// <typeparam name="RegisterImplementation">Type of instance to register that implements RegisterType</typeparam>
/// <param name="instance">Instance of RegisterImplementation to register</param>
/// <param name="name">Name of registration</param>
/// <returns>RegisterOptions for fluent API</returns>
public RegisterOptions Register<RegisterType, RegisterImplementation>(RegisterImplementation instance, string name)
where RegisterType : class
where RegisterImplementation : class, RegisterType
{
return this.Register(typeof(RegisterType), typeof(RegisterImplementation), instance, name);
}
/// <summary>
/// Creates/replaces a container class registration with a user specified factory
/// </summary>
/// <typeparam name="RegisterType">Type to register</typeparam>
/// <param name="factory">Factory/lambda that returns an instance of RegisterType</param>
/// <returns>RegisterOptions for fluent API</returns>
public RegisterOptions Register<RegisterType>(Func<TinyIoCContainer, NamedParameterOverloads, RegisterType> factory)
where RegisterType : class
{
if (factory == null)
{
throw new ArgumentNullException("factory");
}
return this.Register(typeof(RegisterType), (c, o) => factory(c, o));
}
/// <summary>
/// Creates/replaces a named container class registration with a user specified factory
/// </summary>
/// <typeparam name="RegisterType">Type to register</typeparam>
/// <param name="factory">Factory/lambda that returns an instance of RegisterType</param>
/// <param name="name">Name of registation</param>
/// <returns>RegisterOptions for fluent API</returns>
public RegisterOptions Register<RegisterType>(Func<TinyIoCContainer, NamedParameterOverloads, RegisterType> factory, string name)
where RegisterType : class
{
if (factory == null)
{
throw new ArgumentNullException("factory");
}
return this.Register(typeof(RegisterType), (c, o) => factory(c, o), name);
}
/// <summary>
/// Register multiple implementations of a type.
///
/// Internally this registers each implementation using the full name of the class as its registration name.
/// </summary>
/// <typeparam name="RegisterType">Type that each implementation implements</typeparam>
/// <param name="implementationTypes">Types that implement RegisterType</param>
/// <returns>MultiRegisterOptions for the fluent API</returns>
public MultiRegisterOptions RegisterMultiple<RegisterType>(IEnumerable<Type> implementationTypes)
{
return RegisterMultiple(typeof(RegisterType), implementationTypes);
}
/// <summary>
/// Register multiple implementations of a type.
///
/// Internally this registers each implementation using the full name of the class as its registration name.
/// </summary>
/// <param name="registrationType">Type that each implementation implements</param>
/// <param name="implementationTypes">Types that implement RegisterType</param>
/// <returns>MultiRegisterOptions for the fluent API</returns>
public MultiRegisterOptions RegisterMultiple(Type registrationType, IEnumerable<Type> implementationTypes)
{
if (implementationTypes == null)
throw new ArgumentNullException("types", "types is null.");
foreach (var type in implementationTypes)
//#if NETFX_CORE
// if (!registrationType.GetTypeInfo().IsAssignableFrom(type.GetTypeInfo()))
//#else
if (!registrationType.IsAssignableFrom(type))
//#endif
throw new ArgumentException(string.Format("types: The type {0} is not assignable from {1}", registrationType.FullName, type.FullName));
if (implementationTypes.Count() != implementationTypes.Distinct().Count())
{
var queryForDuplicatedTypes = from i in implementationTypes
group i by i
into j
where j.Count() > 1
select j.Key.FullName;
var fullNamesOfDuplicatedTypes = string.Join(",\n", queryForDuplicatedTypes.ToArray());
var multipleRegMessage = string.Format("types: The same implementation type cannot be specified multiple times for {0}\n\n{1}", registrationType.FullName, fullNamesOfDuplicatedTypes);
throw new ArgumentException(multipleRegMessage);
}
var registerOptions = new List<RegisterOptions>();
foreach (var type in implementationTypes)
{
registerOptions.Add(Register(registrationType, type, type.FullName));
}
return new MultiRegisterOptions(registerOptions);
}
#endregion
#region Resolution
/// <summary>
/// Attempts to resolve a type using default options.
/// </summary>
/// <param name="resolveType">Type to resolve</param>
/// <returns>Instance of type</returns>
/// <exception cref="TinyIoCResolutionException">Unable to resolve the type.</exception>
public object Resolve(Type resolveType)
{
return ResolveInternal(new TypeRegistration(resolveType), NamedParameterOverloads.Default, ResolveOptions.Default);
}
/// <summary>
/// Attempts to resolve a type using specified options.
/// </summary>
/// <param name="resolveType">Type to resolve</param>
/// <param name="options">Resolution options</param>
/// <returns>Instance of type</returns>
/// <exception cref="TinyIoCResolutionException">Unable to resolve the type.</exception>
public object Resolve(Type resolveType, ResolveOptions options)
{
return ResolveInternal(new TypeRegistration(resolveType), NamedParameterOverloads.Default, options);
}
/// <summary>
/// Attempts to resolve a type using default options and the supplied name.
///
/// Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists).
/// All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail.
/// </summary>
/// <param name="resolveType">Type to resolve</param>
/// <param name="name">Name of registration</param>
/// <returns>Instance of type</returns>
/// <exception cref="TinyIoCResolutionException">Unable to resolve the type.</exception>
public object Resolve(Type resolveType, string name)
{
return ResolveInternal(new TypeRegistration(resolveType, name), NamedParameterOverloads.Default, ResolveOptions.Default);
}
/// <summary>
/// Attempts to resolve a type using supplied options and name.
///
/// Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists).
/// All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail.
/// </summary>
/// <param name="resolveType">Type to resolve</param>
/// <param name="name">Name of registration</param>
/// <param name="options">Resolution options</param>
/// <returns>Instance of type</returns>
/// <exception cref="TinyIoCResolutionException">Unable to resolve the type.</exception>
public object Resolve(Type resolveType, string name, ResolveOptions options)
{
return ResolveInternal(new TypeRegistration(resolveType, name), NamedParameterOverloads.Default, options);
}
/// <summary>
/// Attempts to resolve a type using default options and the supplied constructor parameters.
///
/// Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists).
/// All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail.
/// </summary>
/// <param name="resolveType">Type to resolve</param>
/// <param name="parameters">User specified constructor parameters</param>
/// <returns>Instance of type</returns>
/// <exception cref="TinyIoCResolutionException">Unable to resolve the type.</exception>
public object Resolve(Type resolveType, NamedParameterOverloads parameters)
{
return ResolveInternal(new TypeRegistration(resolveType), parameters, ResolveOptions.Default);
}
/// <summary>
/// Attempts to resolve a type using specified options and the supplied constructor parameters.
///
/// Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists).
/// All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail.
/// </summary>
/// <param name="resolveType">Type to resolve</param>
/// <param name="parameters">User specified constructor parameters</param>
/// <param name="options">Resolution options</param>
/// <returns>Instance of type</returns>
/// <exception cref="TinyIoCResolutionException">Unable to resolve the type.</exception>
public object Resolve(Type resolveType, NamedParameterOverloads parameters, ResolveOptions options)
{
return ResolveInternal(new TypeRegistration(resolveType), parameters, options);
}
/// <summary>
/// Attempts to resolve a type using default options and the supplied constructor parameters and name.
///
/// Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists).
/// All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail.
/// </summary>
/// <param name="resolveType">Type to resolve</param>
/// <param name="parameters">User specified constructor parameters</param>
/// <param name="name">Name of registration</param>
/// <returns>Instance of type</returns>
/// <exception cref="TinyIoCResolutionException">Unable to resolve the type.</exception>
public object Resolve(Type resolveType, string name, NamedParameterOverloads parameters)
{
return ResolveInternal(new TypeRegistration(resolveType, name), parameters, ResolveOptions.Default);
}
/// <summary>
/// Attempts to resolve a named type using specified options and the supplied constructor parameters.
///
/// Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists).
/// All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail.
/// </summary>
/// <param name="resolveType">Type to resolve</param>
/// <param name="name">Name of registration</param>
/// <param name="parameters">User specified constructor parameters</param>
/// <param name="options">Resolution options</param>
/// <returns>Instance of type</returns>
/// <exception cref="TinyIoCResolutionException">Unable to resolve the type.</exception>
public object Resolve(Type resolveType, string name, NamedParameterOverloads parameters, ResolveOptions options)
{
return ResolveInternal(new TypeRegistration(resolveType, name), parameters, options);
}
/// <summary>
/// Attempts to resolve a type using default options.
/// </summary>
/// <typeparam name="ResolveType">Type to resolve</typeparam>
/// <returns>Instance of type</returns>
/// <exception cref="TinyIoCResolutionException">Unable to resolve the type.</exception>
public ResolveType Resolve<ResolveType>()
where ResolveType : class
{
return (ResolveType)Resolve(typeof(ResolveType));
}
/// <summary>
/// Attempts to resolve a type using specified options.
/// </summary>
/// <typeparam name="ResolveType">Type to resolve</typeparam>
/// <param name="options">Resolution options</param>
/// <returns>Instance of type</returns>
/// <exception cref="TinyIoCResolutionException">Unable to resolve the type.</exception>
public ResolveType Resolve<ResolveType>(ResolveOptions options)
where ResolveType : class
{
return (ResolveType)Resolve(typeof(ResolveType), options);
}
/// <summary>
/// Attempts to resolve a type using default options and the supplied name.
///
/// Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists).
/// All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail.
/// </summary>
/// <typeparam name="ResolveType">Type to resolve</typeparam>
/// <param name="name">Name of registration</param>
/// <returns>Instance of type</returns>
/// <exception cref="TinyIoCResolutionException">Unable to resolve the type.</exception>
public ResolveType Resolve<ResolveType>(string name)
where ResolveType : class
{
return (ResolveType)Resolve(typeof(ResolveType), name);
}
/// <summary>
/// Attempts to resolve a type using supplied options and name.
///
/// Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists).
/// All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail.
/// </summary>
/// <typeparam name="ResolveType">Type to resolve</typeparam>
/// <param name="name">Name of registration</param>
/// <param name="options">Resolution options</param>
/// <returns>Instance of type</returns>
/// <exception cref="TinyIoCResolutionException">Unable to resolve the type.</exception>
public ResolveType Resolve<ResolveType>(string name, ResolveOptions options)
where ResolveType : class
{
return (ResolveType)Resolve(typeof(ResolveType), name, options);
}
/// <summary>
/// Attempts to resolve a type using default options and the supplied constructor parameters.
///
/// Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists).
/// All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail.
/// </summary>
/// <typeparam name="ResolveType">Type to resolve</typeparam>
/// <param name="parameters">User specified constructor parameters</param>
/// <returns>Instance of type</returns>
/// <exception cref="TinyIoCResolutionException">Unable to resolve the type.</exception>
public ResolveType Resolve<ResolveType>(NamedParameterOverloads parameters)
where ResolveType : class
{
return (ResolveType)Resolve(typeof(ResolveType), parameters);
}
/// <summary>
/// Attempts to resolve a type using specified options and the supplied constructor parameters.
///
/// Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists).
/// All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail.
/// </summary>
/// <typeparam name="ResolveType">Type to resolve</typeparam>
/// <param name="parameters">User specified constructor parameters</param>
/// <param name="options">Resolution options</param>
/// <returns>Instance of type</returns>
/// <exception cref="TinyIoCResolutionException">Unable to resolve the type.</exception>
public ResolveType Resolve<ResolveType>(NamedParameterOverloads parameters, ResolveOptions options)
where ResolveType : class
{
return (ResolveType)Resolve(typeof(ResolveType), parameters, options);
}
/// <summary>
/// Attempts to resolve a type using default options and the supplied constructor parameters and name.
///
/// Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists).
/// All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail.
/// </summary>
/// <typeparam name="ResolveType">Type to resolve</typeparam>
/// <param name="parameters">User specified constructor parameters</param>
/// <param name="name">Name of registration</param>
/// <returns>Instance of type</returns>
/// <exception cref="TinyIoCResolutionException">Unable to resolve the type.</exception>
public ResolveType Resolve<ResolveType>(string name, NamedParameterOverloads parameters)
where ResolveType : class
{
return (ResolveType)Resolve(typeof(ResolveType), name, parameters);
}
/// <summary>
/// Attempts to resolve a named type using specified options and the supplied constructor parameters.
///
/// Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists).
/// All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail.
/// </summary>
/// <typeparam name="ResolveType">Type to resolve</typeparam>
/// <param name="name">Name of registration</param>
/// <param name="parameters">User specified constructor parameters</param>
/// <param name="options">Resolution options</param>
/// <returns>Instance of type</returns>
/// <exception cref="TinyIoCResolutionException">Unable to resolve the type.</exception>
public ResolveType Resolve<ResolveType>(string name, NamedParameterOverloads parameters, ResolveOptions options)
where ResolveType : class
{
return (ResolveType)Resolve(typeof(ResolveType), name, parameters, options);
}
/// <summary>
/// Attempts to predict whether a given type can be resolved with default options.
///
/// Note: Resolution may still fail if user defined factory registations fail to construct objects when called.
/// </summary>
/// <param name="resolveType">Type to resolve</param>
/// <param name="name">Name of registration</param>
/// <returns>Bool indicating whether the type can be resolved</returns>
public bool CanResolve(Type resolveType)
{
return CanResolveInternal(new TypeRegistration(resolveType), NamedParameterOverloads.Default, ResolveOptions.Default);
}
/// <summary>
/// Attempts to predict whether a given named type can be resolved with default options.
///
/// Note: Resolution may still fail if user defined factory registations fail to construct objects when called.
/// </summary>
/// <param name="resolveType">Type to resolve</param>
/// <returns>Bool indicating whether the type can be resolved</returns>
private bool CanResolve(Type resolveType, string name)
{
return CanResolveInternal(new TypeRegistration(resolveType, name), NamedParameterOverloads.Default, ResolveOptions.Default);
}
/// <summary>
/// Attempts to predict whether a given type can be resolved with the specified options.
///
/// Note: Resolution may still fail if user defined factory registations fail to construct objects when called.
/// </summary>
/// <param name="resolveType">Type to resolve</param>
/// <param name="name">Name of registration</param>
/// <param name="options">Resolution options</param>
/// <returns>Bool indicating whether the type can be resolved</returns>
public bool CanResolve(Type resolveType, ResolveOptions options)
{
return CanResolveInternal(new TypeRegistration(resolveType), NamedParameterOverloads.Default, options);
}
/// <summary>
/// Attempts to predict whether a given named type can be resolved with the specified options.
///
/// Note: Resolution may still fail if user defined factory registations fail to construct objects when called.
/// </summary>
/// <param name="resolveType">Type to resolve</param>
/// <param name="name">Name of registration</param>
/// <param name="options">Resolution options</param>
/// <returns>Bool indicating whether the type can be resolved</returns>
public bool CanResolve(Type resolveType, string name, ResolveOptions options)
{
return CanResolveInternal(new TypeRegistration(resolveType, name), NamedParameterOverloads.Default, options);
}
/// <summary>
/// Attempts to predict whether a given type can be resolved with the supplied constructor parameters and default options.
///
/// Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists).
/// All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail.
///
/// Note: Resolution may still fail if user defined factory registations fail to construct objects when called.
/// </summary>
/// <param name="resolveType">Type to resolve</param>
/// <param name="parameters">User supplied named parameter overloads</param>
/// <returns>Bool indicating whether the type can be resolved</returns>
public bool CanResolve(Type resolveType, NamedParameterOverloads parameters)
{
return CanResolveInternal(new TypeRegistration(resolveType), parameters, ResolveOptions.Default);
}
/// <summary>
/// Attempts to predict whether a given named type can be resolved with the supplied constructor parameters and default options.
///
/// Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists).
/// All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail.
///
/// Note: Resolution may still fail if user defined factory registations fail to construct objects when called.
/// </summary>
/// <param name="resolveType">Type to resolve</param>
/// <param name="name">Name of registration</param>
/// <param name="parameters">User supplied named parameter overloads</param>
/// <returns>Bool indicating whether the type can be resolved</returns>
public bool CanResolve(Type resolveType, string name, NamedParameterOverloads parameters)
{
return CanResolveInternal(new TypeRegistration(resolveType, name), parameters, ResolveOptions.Default);
}
/// <summary>
/// Attempts to predict whether a given type can be resolved with the supplied constructor parameters options.
///
/// Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists).
/// All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail.
///
/// Note: Resolution may still fail if user defined factory registations fail to construct objects when called.
/// </summary>
/// <param name="resolveType">Type to resolve</param>
/// <param name="parameters">User supplied named parameter overloads</param>
/// <param name="options">Resolution options</param>
/// <returns>Bool indicating whether the type can be resolved</returns>
public bool CanResolve(Type resolveType, NamedParameterOverloads parameters, ResolveOptions options)
{
return CanResolveInternal(new TypeRegistration(resolveType), parameters, options);
}
/// <summary>
/// Attempts to predict whether a given named type can be resolved with the supplied constructor parameters options.
///
/// Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists).
/// All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail.
///
/// Note: Resolution may still fail if user defined factory registations fail to construct objects when called.
/// </summary>
/// <param name="resolveType">Type to resolve</param>
/// <param name="name">Name of registration</param>
/// <param name="parameters">User supplied named parameter overloads</param>
/// <param name="options">Resolution options</param>
/// <returns>Bool indicating whether the type can be resolved</returns>
public bool CanResolve(Type resolveType, string name, NamedParameterOverloads parameters, ResolveOptions options)
{
return CanResolveInternal(new TypeRegistration(resolveType, name), parameters, options);
}
/// <summary>
/// Attempts to predict whether a given type can be resolved with default options.
///
/// Note: Resolution may still fail if user defined factory registations fail to construct objects when called.
/// </summary>
/// <typeparam name="ResolveType">Type to resolve</typeparam>
/// <param name="name">Name of registration</param>
/// <returns>Bool indicating whether the type can be resolved</returns>
public bool CanResolve<ResolveType>()
where ResolveType : class
{
return CanResolve(typeof(ResolveType));
}
/// <summary>
/// Attempts to predict whether a given named type can be resolved with default options.
///
/// Note: Resolution may still fail if user defined factory registations fail to construct objects when called.
/// </summary>
/// <typeparam name="ResolveType">Type to resolve</typeparam>
/// <returns>Bool indicating whether the type can be resolved</returns>
public bool CanResolve<ResolveType>(string name)
where ResolveType : class
{
return CanResolve(typeof(ResolveType), name);
}
/// <summary>
/// Attempts to predict whether a given type can be resolved with the specified options.
///
/// Note: Resolution may still fail if user defined factory registations fail to construct objects when called.
/// </summary>
/// <typeparam name="ResolveType">Type to resolve</typeparam>
/// <param name="name">Name of registration</param>
/// <param name="options">Resolution options</param>
/// <returns>Bool indicating whether the type can be resolved</returns>
public bool CanResolve<ResolveType>(ResolveOptions options)
where ResolveType : class
{
return CanResolve(typeof(ResolveType), options);
}
/// <summary>
/// Attempts to predict whether a given named type can be resolved with the specified options.
///
/// Note: Resolution may still fail if user defined factory registations fail to construct objects when called.
/// </summary>
/// <typeparam name="ResolveType">Type to resolve</typeparam>
/// <param name="name">Name of registration</param>
/// <param name="options">Resolution options</param>
/// <returns>Bool indicating whether the type can be resolved</returns>
public bool CanResolve<ResolveType>(string name, ResolveOptions options)
where ResolveType : class
{
return CanResolve(typeof(ResolveType), name, options);
}
/// <summary>
/// Attempts to predict whether a given type can be resolved with the supplied constructor parameters and default options.
///
/// Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists).
/// All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail.
///
/// Note: Resolution may still fail if user defined factory registations fail to construct objects when called.
/// </summary>
/// <typeparam name="ResolveType">Type to resolve</typeparam>
/// <param name="parameters">User supplied named parameter overloads</param>
/// <returns>Bool indicating whether the type can be resolved</returns>
public bool CanResolve<ResolveType>(NamedParameterOverloads parameters)
where ResolveType : class
{
return CanResolve(typeof(ResolveType), parameters);
}
/// <summary>
/// Attempts to predict whether a given named type can be resolved with the supplied constructor parameters and default options.
///
/// Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists).
/// All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail.
///
/// Note: Resolution may still fail if user defined factory registations fail to construct objects when called.
/// </summary>
/// <typeparam name="ResolveType">Type to resolve</typeparam>
/// <param name="name">Name of registration</param>
/// <param name="parameters">User supplied named parameter overloads</param>
/// <returns>Bool indicating whether the type can be resolved</returns>
public bool CanResolve<ResolveType>(string name, NamedParameterOverloads parameters)
where ResolveType : class
{
return CanResolve(typeof(ResolveType), name, parameters);
}
/// <summary>
/// Attempts to predict whether a given type can be resolved with the supplied constructor parameters options.
///
/// Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists).
/// All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail.
///
/// Note: Resolution may still fail if user defined factory registations fail to construct objects when called.
/// </summary>
/// <typeparam name="ResolveType">Type to resolve</typeparam>
/// <param name="parameters">User supplied named parameter overloads</param>
/// <param name="options">Resolution options</param>
/// <returns>Bool indicating whether the type can be resolved</returns>
public bool CanResolve<ResolveType>(NamedParameterOverloads parameters, ResolveOptions options)
where ResolveType : class
{
return CanResolve(typeof(ResolveType), parameters, options);
}
/// <summary>
/// Attempts to predict whether a given named type can be resolved with the supplied constructor parameters options.
///
/// Parameters are used in conjunction with normal container resolution to find the most suitable constructor (if one exists).
/// All user supplied parameters must exist in at least one resolvable constructor of RegisterType or resolution will fail.
///
/// Note: Resolution may still fail if user defined factory registations fail to construct objects when called.
/// </summary>
/// <typeparam name="ResolveType">Type to resolve</typeparam>
/// <param name="name">Name of registration</param>
/// <param name="parameters">User supplied named parameter overloads</param>
/// <param name="options">Resolution options</param>
/// <returns>Bool indicating whether the type can be resolved</returns>
public bool CanResolve<ResolveType>(string name, NamedParameterOverloads parameters, ResolveOptions options)
where ResolveType : class
{
return CanResolve(typeof(ResolveType), name, parameters, options);
}
/// <summary>
/// Attemps to resolve a type using the default options
/// </summary>
/// <param name="ResolveType">Type to resolve</param>
/// <param name="resolvedType">Resolved type or default if resolve fails</param>
/// <returns>True if resolved sucessfully, false otherwise</returns>
public bool TryResolve(Type resolveType, out object resolvedType)
{
try
{
resolvedType = Resolve(resolveType);
return true;
}
catch (TinyIoCResolutionException)
{
resolvedType = null;
return false;
}
}
/// <summary>
/// Attemps to resolve a type using the given options
/// </summary>
/// <param name="ResolveType">Type to resolve</param>
/// <param name="options">Resolution options</param>
/// <param name="resolvedType">Resolved type or default if resolve fails</param>
/// <returns>True if resolved sucessfully, false otherwise</returns>
public bool TryResolve(Type resolveType, ResolveOptions options, out object resolvedType)
{
try
{
resolvedType = Resolve(resolveType, options);
return true;
}
catch (TinyIoCResolutionException)
{
resolvedType = null;
return false;
}
}
/// <summary>
/// Attemps to resolve a type using the default options and given name
/// </summary>
/// <param name="ResolveType">Type to resolve</param>
/// <param name="name">Name of registration</param>
/// <param name="resolvedType">Resolved type or default if resolve fails</param>
/// <returns>True if resolved sucessfully, false otherwise</returns>
public bool TryResolve(Type resolveType, string name, out object resolvedType)
{
try
{
resolvedType = Resolve(resolveType, name);
return true;
}
catch (TinyIoCResolutionException)
{
resolvedType = null;
return false;
}
}
/// <summary>
/// Attemps to resolve a type using the given options and name
/// </summary>
/// <param name="ResolveType">Type to resolve</param>
/// <param name="name">Name of registration</param>
/// <param name="options">Resolution options</param>
/// <param name="resolvedType">Resolved type or default if resolve fails</param>
/// <returns>True if resolved sucessfully, false otherwise</returns>
public bool TryResolve(Type resolveType, string name, ResolveOptions options, out object resolvedType)
{
try
{
resolvedType = Resolve(resolveType, name, options);
return true;
}
catch (TinyIoCResolutionException)
{
resolvedType = null;
return false;
}
}
/// <summary>
/// Attemps to resolve a type using the default options and supplied constructor parameters
/// </summary>
/// <param name="ResolveType">Type to resolve</param>
/// <param name="parameters">User specified constructor parameters</param>
/// <param name="resolvedType">Resolved type or default if resolve fails</param>
/// <returns>True if resolved sucessfully, false otherwise</returns>
public bool TryResolve(Type resolveType, NamedParameterOverloads parameters, out object resolvedType)
{
try
{
resolvedType = Resolve(resolveType, parameters);
return true;
}
catch (TinyIoCResolutionException)
{
resolvedType = null;
return false;
}
}
/// <summary>
/// Attemps to resolve a type using the default options and supplied name and constructor parameters
/// </summary>
/// <param name="ResolveType">Type to resolve</param>
/// <param name="name">Name of registration</param>
/// <param name="parameters">User specified constructor parameters</param>
/// <param name="resolvedType">Resolved type or default if resolve fails</param>
/// <returns>True if resolved sucessfully, false otherwise</returns>
public bool TryResolve(Type resolveType, string name, NamedParameterOverloads parameters, out object resolvedType)
{
try
{
resolvedType = Resolve(resolveType, name, parameters);
return true;
}
catch (TinyIoCResolutionException)
{
resolvedType = null;
return false;
}
}
/// <summary>
/// Attemps to resolve a type using the supplied options and constructor parameters
/// </summary>
/// <param name="ResolveType">Type to resolve</param>
/// <param name="name">Name of registration</param>
/// <param name="parameters">User specified constructor parameters</param>
/// <param name="options">Resolution options</param>
/// <param name="resolvedType">Resolved type or default if resolve fails</param>
/// <returns>True if resolved sucessfully, false otherwise</returns>
public bool TryResolve(Type resolveType, NamedParameterOverloads parameters, ResolveOptions options, out object resolvedType)
{
try
{
resolvedType = Resolve(resolveType, parameters, options);
return true;
}
catch (TinyIoCResolutionException)
{
resolvedType = null;
return false;
}
}
/// <summary>
/// Attemps to resolve a type using the supplied name, options and constructor parameters
/// </summary>
/// <param name="ResolveType">Type to resolve</param>
/// <param name="name">Name of registration</param>
/// <param name="parameters">User specified constructor parameters</param>
/// <param name="options">Resolution options</param>
/// <param name="resolvedType">Resolved type or default if resolve fails</param>
/// <returns>True if resolved sucessfully, false otherwise</returns>
public bool TryResolve(Type resolveType, string name, NamedParameterOverloads parameters, ResolveOptions options, out object resolvedType)
{
try
{
resolvedType = Resolve(resolveType, name, parameters, options);
return true;
}
catch (TinyIoCResolutionException)
{
resolvedType = null;
return false;
}
}
/// <summary>
/// Attemps to resolve a type using the default options
/// </summary>
/// <typeparam name="ResolveType">Type to resolve</typeparam>
/// <param name="resolvedType">Resolved type or default if resolve fails</param>
/// <returns>True if resolved sucessfully, false otherwise</returns>
public bool TryResolve<ResolveType>(out ResolveType resolvedType)
where ResolveType : class
{
try
{
resolvedType = Resolve<ResolveType>();
return true;
}
catch (TinyIoCResolutionException)
{
resolvedType = default(ResolveType);
return false;
}
}
/// <summary>
/// Attemps to resolve a type using the given options
/// </summary>
/// <typeparam name="ResolveType">Type to resolve</typeparam>
/// <param name="options">Resolution options</param>
/// <param name="resolvedType">Resolved type or default if resolve fails</param>
/// <returns>True if resolved sucessfully, false otherwise</returns>
public bool TryResolve<ResolveType>(ResolveOptions options, out ResolveType resolvedType)
where ResolveType : class
{
try
{
resolvedType = Resolve<ResolveType>(options);
return true;
}
catch (TinyIoCResolutionException)
{
resolvedType = default(ResolveType);
return false;
}
}
/// <summary>
/// Attemps to resolve a type using the default options and given name
/// </summary>
/// <typeparam name="ResolveType">Type to resolve</typeparam>
/// <param name="name">Name of registration</param>
/// <param name="resolvedType">Resolved type or default if resolve fails</param>
/// <returns>True if resolved sucessfully, false otherwise</returns>
public bool TryResolve<ResolveType>(string name, out ResolveType resolvedType)
where ResolveType : class
{
try
{
resolvedType = Resolve<ResolveType>(name);
return true;
}
catch (TinyIoCResolutionException)
{
resolvedType = default(ResolveType);
return false;
}
}
/// <summary>
/// Attemps to resolve a type using the given options and name
/// </summary>
/// <typeparam name="ResolveType">Type to resolve</typeparam>
/// <param name="name">Name of registration</param>
/// <param name="options">Resolution options</param>
/// <param name="resolvedType">Resolved type or default if resolve fails</param>
/// <returns>True if resolved sucessfully, false otherwise</returns>
public bool TryResolve<ResolveType>(string name, ResolveOptions options, out ResolveType resolvedType)
where ResolveType : class
{
try
{
resolvedType = Resolve<ResolveType>(name, options);
return true;
}
catch (TinyIoCResolutionException)
{
resolvedType = default(ResolveType);
return false;
}
}
/// <summary>
/// Attemps to resolve a type using the default options and supplied constructor parameters
/// </summary>
/// <typeparam name="ResolveType">Type to resolve</typeparam>
/// <param name="parameters">User specified constructor parameters</param>
/// <param name="resolvedType">Resolved type or default if resolve fails</param>
/// <returns>True if resolved sucessfully, false otherwise</returns>
public bool TryResolve<ResolveType>(NamedParameterOverloads parameters, out ResolveType resolvedType)
where ResolveType : class
{
try
{
resolvedType = Resolve<ResolveType>(parameters);
return true;
}
catch (TinyIoCResolutionException)
{
resolvedType = default(ResolveType);
return false;
}
}
/// <summary>
/// Attemps to resolve a type using the default options and supplied name and constructor parameters
/// </summary>
/// <typeparam name="ResolveType">Type to resolve</typeparam>
/// <param name="name">Name of registration</param>
/// <param name="parameters">User specified constructor parameters</param>
/// <param name="resolvedType">Resolved type or default if resolve fails</param>
/// <returns>True if resolved sucessfully, false otherwise</returns>
public bool TryResolve<ResolveType>(string name, NamedParameterOverloads parameters, out ResolveType resolvedType)
where ResolveType : class
{
try
{
resolvedType = Resolve<ResolveType>(name, parameters);
return true;
}
catch (TinyIoCResolutionException)
{
resolvedType = default(ResolveType);
return false;
}
}
/// <summary>
/// Attemps to resolve a type using the supplied options and constructor parameters
/// </summary>
/// <typeparam name="ResolveType">Type to resolve</typeparam>
/// <param name="name">Name of registration</param>
/// <param name="parameters">User specified constructor parameters</param>
/// <param name="options">Resolution options</param>
/// <param name="resolvedType">Resolved type or default if resolve fails</param>
/// <returns>True if resolved sucessfully, false otherwise</returns>
public bool TryResolve<ResolveType>(NamedParameterOverloads parameters, ResolveOptions options, out ResolveType resolvedType)
where ResolveType : class
{
try
{
resolvedType = Resolve<ResolveType>(parameters, options);
return true;
}
catch (TinyIoCResolutionException)
{
resolvedType = default(ResolveType);
return false;
}
}
/// <summary>
/// Attemps to resolve a type using the supplied name, options and constructor parameters
/// </summary>
/// <typeparam name="ResolveType">Type to resolve</typeparam>
/// <param name="name">Name of registration</param>
/// <param name="parameters">User specified constructor parameters</param>
/// <param name="options">Resolution options</param>
/// <param name="resolvedType">Resolved type or default if resolve fails</param>
/// <returns>True if resolved sucessfully, false otherwise</returns>
public bool TryResolve<ResolveType>(string name, NamedParameterOverloads parameters, ResolveOptions options, out ResolveType resolvedType)
where ResolveType : class
{
try
{
resolvedType = Resolve<ResolveType>(name, parameters, options);
return true;
}
catch (TinyIoCResolutionException)
{
resolvedType = default(ResolveType);
return false;
}
}
/// <summary>
/// Returns all registrations of a type
/// </summary>
/// <param name="ResolveType">Type to resolveAll</param>
/// <param name="includeUnnamed">Whether to include un-named (default) registrations</param>
/// <returns>IEnumerable</returns>
public IEnumerable<object> ResolveAll(Type resolveType, bool includeUnnamed)
{
return ResolveAllInternal(resolveType, includeUnnamed);
}
/// <summary>
/// Returns all registrations of a type, both named and unnamed
/// </summary>
/// <param name="ResolveType">Type to resolveAll</param>
/// <returns>IEnumerable</returns>
public IEnumerable<object> ResolveAll(Type resolveType)
{
return ResolveAll(resolveType, false);
}
/// <summary>
/// Returns all registrations of a type
/// </summary>
/// <typeparam name="ResolveType">Type to resolveAll</typeparam>
/// <param name="includeUnnamed">Whether to include un-named (default) registrations</param>
/// <returns>IEnumerable</returns>
public IEnumerable<ResolveType> ResolveAll<ResolveType>(bool includeUnnamed)
where ResolveType : class
{
return this.ResolveAll(typeof(ResolveType), includeUnnamed).Cast<ResolveType>();
}
/// <summary>
/// Returns all registrations of a type, both named and unnamed
/// </summary>
/// <typeparam name="ResolveType">Type to resolveAll</typeparam>
/// <param name="includeUnnamed">Whether to include un-named (default) registrations</param>
/// <returns>IEnumerable</returns>
public IEnumerable<ResolveType> ResolveAll<ResolveType>()
where ResolveType : class
{
return ResolveAll<ResolveType>(true);
}
/// <summary>
/// Attempts to resolve all public property dependencies on the given object.
/// </summary>
/// <param name="input">Object to "build up"</param>
public void BuildUp(object input)
{
BuildUpInternal(input, ResolveOptions.Default);
}
/// <summary>
/// Attempts to resolve all public property dependencies on the given object using the given resolve options.
/// </summary>
/// <param name="input">Object to "build up"</param>
/// <param name="resolveOptions">Resolve options to use</param>
public void BuildUp(object input, ResolveOptions resolveOptions)
{
BuildUpInternal(input, resolveOptions);
}
#endregion
#endregion
#region Object Factories
/// <summary>
/// Provides custom lifetime management for ASP.Net per-request lifetimes etc.
/// </summary>
public interface ITinyIoCObjectLifetimeProvider
{
/// <summary>
/// Gets the stored object if it exists, or null if not
/// </summary>
/// <returns>Object instance or null</returns>
object GetObject();
/// <summary>
/// Store the object
/// </summary>
/// <param name="value">Object to store</param>
void SetObject(object value);
/// <summary>
/// Release the object
/// </summary>
void ReleaseObject();
}
private abstract class ObjectFactoryBase
{
/// <summary>
/// Whether to assume this factory sucessfully constructs its objects
///
/// Generally set to true for delegate style factories as CanResolve cannot delve
/// into the delegates they contain.
/// </summary>
public virtual bool AssumeConstruction => false;
/// <summary>
/// The type the factory instantiates
/// </summary>
public abstract Type CreatesType { get; }
/// <summary>
/// Constructor to use, if specified
/// </summary>
public ConstructorInfo Constructor { get; protected set; }
/// <summary>
/// Create the type
/// </summary>
/// <param name="requestedType">Type user requested to be resolved</param>
/// <param name="container">Container that requested the creation</param>
/// <param name="parameters">Any user parameters passed</param>
/// <param name="options"></param>
/// <returns></returns>
public abstract object GetObject(Type requestedType, TinyIoCContainer container, NamedParameterOverloads parameters, ResolveOptions options);
public virtual ObjectFactoryBase SingletonVariant
{
get
{
throw new TinyIoCRegistrationException(this.GetType(), "singleton");
}
}
public virtual ObjectFactoryBase MultiInstanceVariant
{
get
{
throw new TinyIoCRegistrationException(this.GetType(), "multi-instance");
}
}
public virtual ObjectFactoryBase StrongReferenceVariant
{
get
{
throw new TinyIoCRegistrationException(this.GetType(), "strong reference");
}
}
public virtual ObjectFactoryBase WeakReferenceVariant
{
get
{
throw new TinyIoCRegistrationException(this.GetType(), "weak reference");
}
}
public virtual ObjectFactoryBase GetCustomObjectLifetimeVariant(ITinyIoCObjectLifetimeProvider lifetimeProvider, string errorString)
{
throw new TinyIoCRegistrationException(this.GetType(), errorString);
}
public virtual void SetConstructor(ConstructorInfo constructor)
{
Constructor = constructor;
}
public virtual ObjectFactoryBase GetFactoryForChildContainer(Type type, TinyIoCContainer parent, TinyIoCContainer child)
{
return this;
}
}
/// <summary>
/// IObjectFactory that creates new instances of types for each resolution
/// </summary>
private class MultiInstanceFactory : ObjectFactoryBase
{
private readonly Type registerType;
private readonly Type registerImplementation;
public override Type CreatesType => this.registerImplementation;
public MultiInstanceFactory(Type registerType, Type registerImplementation)
{
//#if NETFX_CORE
// if (registerImplementation.GetTypeInfo().IsAbstract() || registerImplementation.GetTypeInfo().IsInterface())
// throw new TinyIoCRegistrationTypeException(registerImplementation, "MultiInstanceFactory");
//#else
if (registerImplementation.IsAbstract() || registerImplementation.IsInterface())
throw new TinyIoCRegistrationTypeException(registerImplementation, "MultiInstanceFactory");
//#endif
if (!IsValidAssignment(registerType, registerImplementation))
throw new TinyIoCRegistrationTypeException(registerImplementation, "MultiInstanceFactory");
this.registerType = registerType;
this.registerImplementation = registerImplementation;
}
public override object GetObject(Type requestedType, TinyIoCContainer container, NamedParameterOverloads parameters, ResolveOptions options)
{
try
{
return container.ConstructType(requestedType, this.registerImplementation, Constructor, parameters, options);
}
catch (TinyIoCResolutionException ex)
{
throw new TinyIoCResolutionException(this.registerType, ex);
}
}
public override ObjectFactoryBase SingletonVariant => new SingletonFactory(this.registerType, this.registerImplementation);
public override ObjectFactoryBase GetCustomObjectLifetimeVariant(ITinyIoCObjectLifetimeProvider lifetimeProvider, string errorString)
{
return new CustomObjectLifetimeFactory(this.registerType, this.registerImplementation, lifetimeProvider, errorString);
}
public override ObjectFactoryBase MultiInstanceVariant => this;
}
/// <summary>
/// IObjectFactory that invokes a specified delegate to construct the object
/// </summary>
private class DelegateFactory : ObjectFactoryBase
{
private readonly Type registerType;
private Func<TinyIoCContainer, NamedParameterOverloads, object> _factory;
public override bool AssumeConstruction => true;
public override Type CreatesType => this.registerType;
public override object GetObject(Type requestedType, TinyIoCContainer container, NamedParameterOverloads parameters, ResolveOptions options)
{
try
{
return _factory.Invoke(container, parameters);
}
catch (Exception ex)
{
throw new TinyIoCResolutionException(this.registerType, ex);
}
}
public DelegateFactory(Type registerType, Func<TinyIoCContainer, NamedParameterOverloads, object> factory)
{
if (factory == null)
throw new ArgumentNullException("factory");
_factory = factory;
this.registerType = registerType;
}
public override ObjectFactoryBase WeakReferenceVariant => new WeakDelegateFactory(this.registerType, _factory);
public override ObjectFactoryBase StrongReferenceVariant => this;
public override void SetConstructor(ConstructorInfo constructor)
{
throw new TinyIoCConstructorResolutionException("Constructor selection is not possible for delegate factory registrations");
}
}
/// <summary>
/// IObjectFactory that invokes a specified delegate to construct the object
/// Holds the delegate using a weak reference
/// </summary>
private class WeakDelegateFactory : ObjectFactoryBase
{
private readonly Type registerType;
private WeakReference _factory;
public override bool AssumeConstruction => true;
public override Type CreatesType => this.registerType;
public override object GetObject(Type requestedType, TinyIoCContainer container, NamedParameterOverloads parameters, ResolveOptions options)
{
var factory = _factory.Target as Func<TinyIoCContainer, NamedParameterOverloads, object>;
if (factory == null)
throw new TinyIoCWeakReferenceException(this.registerType);
try
{
return factory.Invoke(container, parameters);
}
catch (Exception ex)
{
throw new TinyIoCResolutionException(this.registerType, ex);
}
}
public WeakDelegateFactory(Type registerType, Func<TinyIoCContainer, NamedParameterOverloads, object> factory)
{
if (factory == null)
throw new ArgumentNullException("factory");
_factory = new WeakReference(factory);
this.registerType = registerType;
}
public override ObjectFactoryBase StrongReferenceVariant
{
get
{
var factory = _factory.Target as Func<TinyIoCContainer, NamedParameterOverloads, object>;
if (factory == null)
throw new TinyIoCWeakReferenceException(this.registerType);
return new DelegateFactory(this.registerType, factory);
}
}
public override ObjectFactoryBase WeakReferenceVariant => this;
public override void SetConstructor(ConstructorInfo constructor)
{
throw new TinyIoCConstructorResolutionException("Constructor selection is not possible for delegate factory registrations");
}
}
/// <summary>
/// Stores an particular instance to return for a type
/// </summary>
private class InstanceFactory : ObjectFactoryBase, IDisposable
{
private readonly Type registerType;
private readonly Type registerImplementation;
private object _instance;
public override bool AssumeConstruction => true;
public InstanceFactory(Type registerType, Type registerImplementation, object instance)
{
if (!IsValidAssignment(registerType, registerImplementation))
throw new TinyIoCRegistrationTypeException(registerImplementation, "InstanceFactory");
this.registerType = registerType;
this.registerImplementation = registerImplementation;
_instance = instance;
}
public override Type CreatesType => this.registerImplementation;
public override object GetObject(Type requestedType, TinyIoCContainer container, NamedParameterOverloads parameters, ResolveOptions options)
{
return _instance;
}
public override ObjectFactoryBase MultiInstanceVariant => new MultiInstanceFactory(this.registerType, this.registerImplementation);
public override ObjectFactoryBase WeakReferenceVariant => new WeakInstanceFactory(this.registerType, this.registerImplementation, this._instance);
public override ObjectFactoryBase StrongReferenceVariant => this;
public override void SetConstructor(ConstructorInfo constructor)
{
throw new TinyIoCConstructorResolutionException("Constructor selection is not possible for instance factory registrations");
}
public void Dispose()
{
var disposable = _instance as IDisposable;
if (disposable != null)
disposable.Dispose();
}
}
/// <summary>
/// Stores an particular instance to return for a type
///
/// Stores the instance with a weak reference
/// </summary>
private class WeakInstanceFactory : ObjectFactoryBase, IDisposable
{
private readonly Type registerType;
private readonly Type registerImplementation;
private readonly WeakReference _instance;
public WeakInstanceFactory(Type registerType, Type registerImplementation, object instance)
{
if (!IsValidAssignment(registerType, registerImplementation))
throw new TinyIoCRegistrationTypeException(registerImplementation, "WeakInstanceFactory");
this.registerType = registerType;
this.registerImplementation = registerImplementation;
_instance = new WeakReference(instance);
}
public override Type CreatesType => this.registerImplementation;
public override object GetObject(Type requestedType, TinyIoCContainer container, NamedParameterOverloads parameters, ResolveOptions options)
{
var instance = _instance.Target;
if (instance == null)
throw new TinyIoCWeakReferenceException(this.registerType);
return instance;
}
public override ObjectFactoryBase MultiInstanceVariant => new MultiInstanceFactory(this.registerType, this.registerImplementation);
public override ObjectFactoryBase WeakReferenceVariant => this;
public override ObjectFactoryBase StrongReferenceVariant
{
get
{
var instance = _instance.Target;
if (instance == null)
throw new TinyIoCWeakReferenceException(this.registerType);
return new InstanceFactory(this.registerType, this.registerImplementation, instance);
}
}
public override void SetConstructor(ConstructorInfo constructor)
{
throw new TinyIoCConstructorResolutionException("Constructor selection is not possible for instance factory registrations");
}
public void Dispose()
{
var disposable = _instance.Target as IDisposable;
if (disposable != null)
disposable.Dispose();
}
}
/// <summary>
/// A factory that lazy instantiates a type and always returns the same instance
/// </summary>
private class SingletonFactory : ObjectFactoryBase, IDisposable
{
private readonly Type registerType;
private readonly Type registerImplementation;
private readonly object SingletonLock = new object();
private object _Current;
public SingletonFactory(Type registerType, Type registerImplementation)
{
//#if NETFX_CORE
// if (registerImplementation.GetTypeInfo().IsAbstract() || registerImplementation.GetTypeInfo().IsInterface())
//#else
if (registerImplementation.IsAbstract() || registerImplementation.IsInterface())
//#endif
throw new TinyIoCRegistrationTypeException(registerImplementation, "SingletonFactory");
if (!IsValidAssignment(registerType, registerImplementation))
throw new TinyIoCRegistrationTypeException(registerImplementation, "SingletonFactory");
this.registerType = registerType;
this.registerImplementation = registerImplementation;
}
public override Type CreatesType => this.registerImplementation;
public override object GetObject(Type requestedType, TinyIoCContainer container, NamedParameterOverloads parameters, ResolveOptions options)
{
if (parameters.Count != 0)
throw new ArgumentException("Cannot specify parameters for singleton types");
lock (SingletonLock)
if (_Current == null)
_Current = container.ConstructType(requestedType, this.registerImplementation, Constructor, options);
return _Current;
}
public override ObjectFactoryBase SingletonVariant => this;
public override ObjectFactoryBase GetCustomObjectLifetimeVariant(ITinyIoCObjectLifetimeProvider lifetimeProvider, string errorString)
{
return new CustomObjectLifetimeFactory(this.registerType, this.registerImplementation, lifetimeProvider, errorString);
}
public override ObjectFactoryBase MultiInstanceVariant => new MultiInstanceFactory(this.registerType, this.registerImplementation);
public override ObjectFactoryBase GetFactoryForChildContainer(Type type, TinyIoCContainer parent, TinyIoCContainer child)
{
// We make sure that the singleton is constructed before the child container takes the factory.
// Otherwise the results would vary depending on whether or not the parent container had resolved
// the type before the child container does.
GetObject(type, parent, NamedParameterOverloads.Default, ResolveOptions.Default);
return this;
}
public void Dispose()
{
if (this._Current == null)
return;
var disposable = this._Current as IDisposable;
if (disposable != null)
disposable.Dispose();
}
}
/// <summary>
/// A factory that offloads lifetime to an external lifetime provider
/// </summary>
private class CustomObjectLifetimeFactory : ObjectFactoryBase, IDisposable
{
private readonly object SingletonLock = new object();
private readonly Type registerType;
private readonly Type registerImplementation;
private readonly ITinyIoCObjectLifetimeProvider _LifetimeProvider;
public CustomObjectLifetimeFactory(Type registerType, Type registerImplementation, ITinyIoCObjectLifetimeProvider lifetimeProvider, string errorMessage)
{
if (lifetimeProvider == null)
throw new ArgumentNullException("lifetimeProvider", "lifetimeProvider is null.");
if (!IsValidAssignment(registerType, registerImplementation))
throw new TinyIoCRegistrationTypeException(registerImplementation, "SingletonFactory");
//#if NETFX_CORE
// if (registerImplementation.GetTypeInfo().IsAbstract() || registerImplementation.GetTypeInfo().IsInterface())
//#else
if (registerImplementation.IsAbstract() || registerImplementation.IsInterface())
//#endif
throw new TinyIoCRegistrationTypeException(registerImplementation, errorMessage);
this.registerType = registerType;
this.registerImplementation = registerImplementation;
_LifetimeProvider = lifetimeProvider;
}
public override Type CreatesType => this.registerImplementation;
public override object GetObject(Type requestedType, TinyIoCContainer container, NamedParameterOverloads parameters, ResolveOptions options)
{
object current;
lock (SingletonLock)
{
current = _LifetimeProvider.GetObject();
if (current == null)
{
current = container.ConstructType(requestedType, this.registerImplementation, Constructor, options);
_LifetimeProvider.SetObject(current);
}
}
return current;
}
public override ObjectFactoryBase SingletonVariant
{
get
{
_LifetimeProvider.ReleaseObject();
return new SingletonFactory(this.registerType, this.registerImplementation);
}
}
public override ObjectFactoryBase MultiInstanceVariant
{
get
{
_LifetimeProvider.ReleaseObject();
return new MultiInstanceFactory(this.registerType, this.registerImplementation);
}
}
public override ObjectFactoryBase GetCustomObjectLifetimeVariant(ITinyIoCObjectLifetimeProvider lifetimeProvider, string errorString)
{
_LifetimeProvider.ReleaseObject();
return new CustomObjectLifetimeFactory(this.registerType, this.registerImplementation, lifetimeProvider, errorString);
}
public override ObjectFactoryBase GetFactoryForChildContainer(Type type, TinyIoCContainer parent, TinyIoCContainer child)
{
// We make sure that the singleton is constructed before the child container takes the factory.
// Otherwise the results would vary depending on whether or not the parent container had resolved
// the type before the child container does.
GetObject(type, parent, NamedParameterOverloads.Default, ResolveOptions.Default);
return this;
}
public void Dispose()
{
_LifetimeProvider.ReleaseObject();
}
}
#endregion
#region Singleton Container
private static readonly TinyIoCContainer _Current = new TinyIoCContainer();
static TinyIoCContainer()
{
}
/// <summary>
/// Lazy created Singleton instance of the container for simple scenarios
/// </summary>
public static TinyIoCContainer Current => _Current;
#endregion
#region Type Registrations
public sealed class TypeRegistration
{
private int _hashCode;
public Type Type { get; private set; }
public string Name { get; private set; }
public TypeRegistration(Type type)
: this(type, string.Empty)
{
}
public TypeRegistration(Type type, string name)
{
Type = type;
Name = name;
_hashCode = string.Concat(Type.FullName, "|", Name).GetHashCode();
}
public override bool Equals(object obj)
{
var typeRegistration = obj as TypeRegistration;
if (typeRegistration == null)
return false;
if (Type != typeRegistration.Type)
return false;
if (string.Compare(Name, typeRegistration.Name, StringComparison.Ordinal) != 0)
return false;
return true;
}
public override int GetHashCode()
{
return _hashCode;
}
}
private readonly SafeDictionary<TypeRegistration, ObjectFactoryBase> _RegisteredTypes;
#if USE_OBJECT_CONSTRUCTOR
private delegate object ObjectConstructor(params object[] parameters);
private static readonly SafeDictionary<ConstructorInfo, ObjectConstructor> _ObjectConstructorCache = new SafeDictionary<ConstructorInfo, ObjectConstructor>();
#endif
#endregion
#region Constructors
public TinyIoCContainer()
{
_RegisteredTypes = new SafeDictionary<TypeRegistration, ObjectFactoryBase>();
RegisterDefaultTypes();
}
TinyIoCContainer _Parent;
private TinyIoCContainer(TinyIoCContainer parent)
: this()
{
_Parent = parent;
}
#endregion
#region Internal Methods
private readonly object _AutoRegisterLock = new object();
private void AutoRegisterInternal(IEnumerable<Assembly> assemblies, DuplicateImplementationActions duplicateAction, Func<Type, bool> registrationPredicate)
{
lock (_AutoRegisterLock)
{
var types = assemblies.SelectMany(a => a.SafeGetTypes()).Where(t => !IsIgnoredType(t, registrationPredicate)).ToList();
var concreteTypes = from type in types
where type.IsClass() && (type.IsAbstract() == false) && (type != this.GetType() && (type.DeclaringType != this.GetType()) && (!type.IsGenericTypeDefinition()))
select type;
foreach (var type in concreteTypes)
{
try
{
RegisterInternal(type, string.Empty, GetDefaultObjectFactory(type, type));
}
catch (MethodAccessException)
{
// Ignore methods we can't access - added for Silverlight
}
}
var abstractInterfaceTypes = from type in types
where ((type.IsInterface() || type.IsAbstract()) && (type.DeclaringType != this.GetType()) && (!type.IsGenericTypeDefinition()))
select type;
foreach (var type in abstractInterfaceTypes)
{
var localType = type;
var implementations = from implementationType in concreteTypes
where localType.IsAssignableFrom(implementationType)
select implementationType;
if (implementations.Count() > 1)
{
if (duplicateAction == DuplicateImplementationActions.Fail)
throw new TinyIoCAutoRegistrationException(type, implementations);
if (duplicateAction == DuplicateImplementationActions.RegisterMultiple)
{
RegisterMultiple(type, implementations);
}
}
var firstImplementation = implementations.FirstOrDefault();
if (firstImplementation != null)
{
try
{
RegisterInternal(type, string.Empty, GetDefaultObjectFactory(type, firstImplementation));
}
catch (MethodAccessException)
{
// Ignore methods we can't access - added for Silverlight
}
}
}
}
}
private bool IsIgnoredAssembly(Assembly assembly)
{
// TODO - find a better way to remove "system" assemblies from the auto registration
var ignoreChecks = new List<Func<Assembly, bool>>()
{
asm => asm.FullName.StartsWith("Microsoft.", StringComparison.Ordinal),
asm => asm.FullName.StartsWith("System.", StringComparison.Ordinal),
asm => asm.FullName.StartsWith("System,", StringComparison.Ordinal),
asm => asm.FullName.StartsWith("CR_ExtUnitTest", StringComparison.Ordinal),
asm => asm.FullName.StartsWith("mscorlib,", StringComparison.Ordinal),
asm => asm.FullName.StartsWith("CR_VSTest", StringComparison.Ordinal),
asm => asm.FullName.StartsWith("DevExpress.CodeRush", StringComparison.Ordinal),
};
foreach (var check in ignoreChecks)
{
if (check(assembly))
return true;
}
return false;
}
private bool IsIgnoredType(Type type, Func<Type, bool> registrationPredicate)
{
// TODO - find a better way to remove "system" types from the auto registration
var ignoreChecks = new List<Func<Type, bool>>()
{
t => t.FullName.StartsWith("System.", StringComparison.Ordinal),
t => t.FullName.StartsWith("Microsoft.", StringComparison.Ordinal),
t => t.IsPrimitive(),
#if !UNBOUND_GENERICS_GETCONSTRUCTORS
t => t.IsGenericTypeDefinition(),
#endif
t => (t.GetConstructors(BindingFlags.Instance | BindingFlags.Public).Length == 0) && !(t.IsInterface() || t.IsAbstract()),
};
if (registrationPredicate != null)
{
ignoreChecks.Add(t => !registrationPredicate(t));
}
foreach (var check in ignoreChecks)
{
if (check(type))
return true;
}
return false;
}
private void RegisterDefaultTypes()
{
Register<TinyIoCContainer>(this);
#if TINYMESSENGER
// Only register the TinyMessenger singleton if we are the root container
if (_Parent == null)
Register<TinyMessenger.ITinyMessengerHub, TinyMessenger.TinyMessengerHub>();
#endif
}
private ObjectFactoryBase GetCurrentFactory(TypeRegistration registration)
{
ObjectFactoryBase current = null;
_RegisteredTypes.TryGetValue(registration, out current);
return current;
}
private RegisterOptions RegisterInternal(Type registerType, string name, ObjectFactoryBase factory)
{
var typeRegistration = new TypeRegistration(registerType, name);
return AddUpdateRegistration(typeRegistration, factory);
}
private RegisterOptions AddUpdateRegistration(TypeRegistration typeRegistration, ObjectFactoryBase factory)
{
_RegisteredTypes[typeRegistration] = factory;
return new RegisterOptions(this, typeRegistration);
}
private void RemoveRegistration(TypeRegistration typeRegistration)
{
_RegisteredTypes.Remove(typeRegistration);
}
private ObjectFactoryBase GetDefaultObjectFactory(Type registerType, Type registerImplementation)
{
//#if NETFX_CORE
// if (registerType.GetTypeInfo().IsInterface() || registerType.GetTypeInfo().IsAbstract())
//#else
if (registerType.IsInterface() || registerType.IsAbstract())
//#endif
return new SingletonFactory(registerType, registerImplementation);
return new MultiInstanceFactory(registerType, registerImplementation);
}
private bool CanResolveInternal(TypeRegistration registration, NamedParameterOverloads parameters, ResolveOptions options)
{
if (parameters == null)
throw new ArgumentNullException("parameters");
Type checkType = registration.Type;
string name = registration.Name;
ObjectFactoryBase factory;
if (_RegisteredTypes.TryGetValue(new TypeRegistration(checkType, name), out factory))
{
if (factory.AssumeConstruction)
return true;
if (factory.Constructor == null)
return (GetBestConstructor(factory.CreatesType, parameters, options) != null) ? true : false;
else
return CanConstruct(factory.Constructor, parameters, options);
}
// Fail if requesting named resolution and settings set to fail if unresolved
// Or bubble up if we have a parent
if (!string.IsNullOrEmpty(name) && options.NamedResolutionFailureAction == NamedResolutionFailureActions.Fail)
return (_Parent != null) ? _Parent.CanResolveInternal(registration, parameters, options) : false;
// Attemped unnamed fallback container resolution if relevant and requested
if (!string.IsNullOrEmpty(name) && options.NamedResolutionFailureAction == NamedResolutionFailureActions.AttemptUnnamedResolution)
{
if (_RegisteredTypes.TryGetValue(new TypeRegistration(checkType), out factory))
{
if (factory.AssumeConstruction)
return true;
return (GetBestConstructor(factory.CreatesType, parameters, options) != null) ? true : false;
}
}
// Check if type is an automatic lazy factory request
if (IsAutomaticLazyFactoryRequest(checkType))
return true;
// Check if type is an IEnumerable<ResolveType>
if (IsIEnumerableRequest(registration.Type))
return true;
// Attempt unregistered construction if possible and requested
// If we cant', bubble if we have a parent
if ((options.UnregisteredResolutionAction == UnregisteredResolutionActions.AttemptResolve) || (checkType.IsGenericType() && options.UnregisteredResolutionAction == UnregisteredResolutionActions.GenericsOnly))
return (GetBestConstructor(checkType, parameters, options) != null) ? true : (_Parent != null) ? _Parent.CanResolveInternal(registration, parameters, options) : false;
// Bubble resolution up the container tree if we have a parent
if (_Parent != null)
return _Parent.CanResolveInternal(registration, parameters, options);
return false;
}
private bool IsIEnumerableRequest(Type type)
{
if (!type.IsGenericType())
return false;
Type genericType = type.GetGenericTypeDefinition();
if (genericType == typeof(IEnumerable<>))
return true;
return false;
}
private bool IsAutomaticLazyFactoryRequest(Type type)
{
if (!type.IsGenericType())
return false;
Type genericType = type.GetGenericTypeDefinition();
// Just a func
if (genericType == typeof(Func<>))
return true;
// 2 parameter func with string as first parameter (name)
//#if NETFX_CORE
// if ((genericType == typeof(Func<,>) && type.GetTypeInfo().GenericTypeArguments[0] == typeof(string)))
//#else
if ((genericType == typeof(Func<,>) && type.GetGenericArguments()[0] == typeof(string)))
//#endif
return true;
// 3 parameter func with string as first parameter (name) and IDictionary<string, object> as second (parameters)
//#if NETFX_CORE
// if ((genericType == typeof(Func<,,>) && type.GetTypeInfo().GenericTypeArguments[0] == typeof(string) && type.GetTypeInfo().GenericTypeArguments[1] == typeof(IDictionary<String, object>)))
//#else
if ((genericType == typeof(Func<,,>) && type.GetGenericArguments()[0] == typeof(string) && type.GetGenericArguments()[1] == typeof(IDictionary<string, object>)))
//#endif
return true;
return false;
}
private ObjectFactoryBase GetParentObjectFactory(TypeRegistration registration)
{
if (_Parent == null)
return null;
ObjectFactoryBase factory;
if (_Parent._RegisteredTypes.TryGetValue(registration, out factory))
{
return factory.GetFactoryForChildContainer(registration.Type, _Parent, this);
}
return _Parent.GetParentObjectFactory(registration);
}
private object ResolveInternal(TypeRegistration registration, NamedParameterOverloads parameters, ResolveOptions options)
{
ObjectFactoryBase factory;
// Attempt container resolution
if (_RegisteredTypes.TryGetValue(registration, out factory))
{
try
{
return factory.GetObject(registration.Type, this, parameters, options);
}
catch (TinyIoCResolutionException)
{
throw;
}
catch (Exception ex)
{
throw new TinyIoCResolutionException(registration.Type, ex);
}
}
#if RESOLVE_OPEN_GENERICS
// Attempt container resolution of open generic
if (registration.Type.IsGenericType())
{
var openTypeRegistration = new TypeRegistration(registration.Type.GetGenericTypeDefinition(),
registration.Name);
if (_RegisteredTypes.TryGetValue(openTypeRegistration, out factory))
{
try
{
return factory.GetObject(registration.Type, this, parameters, options);
}
catch (TinyIoCResolutionException)
{
throw;
}
catch (Exception ex)
{
throw new TinyIoCResolutionException(registration.Type, ex);
}
}
}
#endif
// Attempt to get a factory from parent if we can
var bubbledObjectFactory = GetParentObjectFactory(registration);
if (bubbledObjectFactory != null)
{
try
{
return bubbledObjectFactory.GetObject(registration.Type, this, parameters, options);
}
catch (TinyIoCResolutionException)
{
throw;
}
catch (Exception ex)
{
throw new TinyIoCResolutionException(registration.Type, ex);
}
}
// Fail if requesting named resolution and settings set to fail if unresolved
if (!string.IsNullOrEmpty(registration.Name) && options.NamedResolutionFailureAction == NamedResolutionFailureActions.Fail)
throw new TinyIoCResolutionException(registration.Type);
// Attemped unnamed fallback container resolution if relevant and requested
if (!string.IsNullOrEmpty(registration.Name) && options.NamedResolutionFailureAction == NamedResolutionFailureActions.AttemptUnnamedResolution)
{
if (_RegisteredTypes.TryGetValue(new TypeRegistration(registration.Type, string.Empty), out factory))
{
try
{
return factory.GetObject(registration.Type, this, parameters, options);
}
catch (TinyIoCResolutionException)
{
throw;
}
catch (Exception ex)
{
throw new TinyIoCResolutionException(registration.Type, ex);
}
}
}
#if EXPRESSIONS
// Attempt to construct an automatic lazy factory if possible
if (IsAutomaticLazyFactoryRequest(registration.Type))
return GetLazyAutomaticFactoryRequest(registration.Type);
#endif
if (IsIEnumerableRequest(registration.Type))
return GetIEnumerableRequest(registration.Type);
// Attempt unregistered construction if possible and requested
if ((options.UnregisteredResolutionAction == UnregisteredResolutionActions.AttemptResolve) || (registration.Type.IsGenericType() && options.UnregisteredResolutionAction == UnregisteredResolutionActions.GenericsOnly))
{
if (!registration.Type.IsAbstract() && !registration.Type.IsInterface())
return ConstructType(null, registration.Type, parameters, options);
}
// Unable to resolve - throw
throw new TinyIoCResolutionException(registration.Type);
}
#if EXPRESSIONS
private object GetLazyAutomaticFactoryRequest(Type type)
{
if (!type.IsGenericType())
return null;
Type genericType = type.GetGenericTypeDefinition();
//#if NETFX_CORE
// Type[] genericArguments = type.GetTypeInfo().GenericTypeArguments.ToArray();
//#else
Type[] genericArguments = type.GetGenericArguments();
//#endif
// Just a func
if (genericType == typeof(Func<>))
{
Type returnType = genericArguments[0];
//#if NETFX_CORE
// MethodInfo resolveMethod = typeof(TinyIoCContainer).GetTypeInfo().GetDeclaredMethods("Resolve").First(mi => !mi.GetParameters().Any());
//#else
MethodInfo resolveMethod = typeof(TinyIoCContainer).GetMethod("Resolve", new Type[] { });
//#endif
resolveMethod = resolveMethod.MakeGenericMethod(returnType);
var resolveCall = Expression.Call(Expression.Constant(this), resolveMethod);
var resolveLambda = Expression.Lambda(resolveCall).Compile();
return resolveLambda;
}
// 2 parameter func with string as first parameter (name)
if ((genericType == typeof(Func<,>)) && (genericArguments[0] == typeof(string)))
{
Type returnType = genericArguments[1];
//#if NETFX_CORE
// MethodInfo resolveMethod = typeof(TinyIoCContainer).GetTypeInfo().GetDeclaredMethods("Resolve").First(mi => mi.GetParameters().Length == 1 && mi.GetParameters()[0].GetType() == typeof(String));
//#else
MethodInfo resolveMethod = typeof(TinyIoCContainer).GetMethod("Resolve", new Type[] { typeof(string) });
//#endif
resolveMethod = resolveMethod.MakeGenericMethod(returnType);
ParameterExpression[] resolveParameters = new ParameterExpression[] { Expression.Parameter(typeof(string), "name") };
var resolveCall = Expression.Call(Expression.Constant(this), resolveMethod, resolveParameters);
var resolveLambda = Expression.Lambda(resolveCall, resolveParameters).Compile();
return resolveLambda;
}
// 3 parameter func with string as first parameter (name) and IDictionary<string, object> as second (parameters)
//#if NETFX_CORE
// if ((genericType == typeof(Func<,,>) && type.GenericTypeArguments[0] == typeof(string) && type.GenericTypeArguments[1] == typeof(IDictionary<string, object>)))
//#else
if ((genericType == typeof(Func<,,>) && type.GetGenericArguments()[0] == typeof(string) && type.GetGenericArguments()[1] == typeof(IDictionary<string, object>)))
//#endif
{
Type returnType = genericArguments[2];
var name = Expression.Parameter(typeof(string), "name");
var parameters = Expression.Parameter(typeof(IDictionary<string, object>), "parameters");
//#if NETFX_CORE
// MethodInfo resolveMethod = typeof(TinyIoCContainer).GetTypeInfo().GetDeclaredMethods("Resolve").First(mi => mi.GetParameters().Length == 2 && mi.GetParameters()[0].GetType() == typeof(String) && mi.GetParameters()[1].GetType() == typeof(NamedParameterOverloads));
//#else
MethodInfo resolveMethod = typeof(TinyIoCContainer).GetMethod("Resolve", new Type[] { typeof(string), typeof(NamedParameterOverloads) });
//#endif
resolveMethod = resolveMethod.MakeGenericMethod(returnType);
var resolveCall = Expression.Call(Expression.Constant(this), resolveMethod, name, Expression.Call(typeof(NamedParameterOverloads), "FromIDictionary", null, parameters));
var resolveLambda = Expression.Lambda(resolveCall, name, parameters).Compile();
return resolveLambda;
}
throw new TinyIoCResolutionException(type);
}
#endif
private object GetIEnumerableRequest(Type type)
{
//#if NETFX_CORE
// var genericResolveAllMethod = this.GetType().GetGenericMethod("ResolveAll", type.GenericTypeArguments, new[] { typeof(bool) });
//#else
var genericResolveAllMethod = this.GetType().GetGenericMethod(BindingFlags.Public | BindingFlags.Instance, "ResolveAll", type.GetGenericArguments(), new[] { typeof(bool) });
//#endif
return genericResolveAllMethod.Invoke(this, new object[] { false });
}
private bool CanConstruct(ConstructorInfo ctor, NamedParameterOverloads parameters, ResolveOptions options)
{
if (parameters == null)
throw new ArgumentNullException("parameters");
foreach (var parameter in ctor.GetParameters())
{
if (string.IsNullOrEmpty(parameter.Name))
return false;
var isParameterOverload = parameters.ContainsKey(parameter.Name);
//#if NETFX_CORE
// if (parameter.ParameterType.GetTypeInfo().IsPrimitive && !isParameterOverload)
//#else
if (parameter.ParameterType.IsPrimitive() && !isParameterOverload)
//#endif
return false;
if (!isParameterOverload && !CanResolveInternal(new TypeRegistration(parameter.ParameterType), NamedParameterOverloads.Default, options))
return false;
}
return true;
}
private ConstructorInfo GetBestConstructor(Type type, NamedParameterOverloads parameters, ResolveOptions options)
{
if (parameters == null)
throw new ArgumentNullException("parameters");
//#if NETFX_CORE
// if (type.GetTypeInfo().IsValueType)
//#else
if (type.IsValueType())
//#endif
return null;
// Get constructors in reverse order based on the number of parameters
// i.e. be as "greedy" as possible so we satify the most amount of dependencies possible
var ctors = this.GetTypeConstructors(type);
foreach (var ctor in ctors)
{
if (this.CanConstruct(ctor, parameters, options))
return ctor;
}
return null;
}
private IEnumerable<ConstructorInfo> GetTypeConstructors(Type type)
{
//#if NETFX_CORE
// return type.GetTypeInfo().DeclaredConstructors.OrderByDescending(ctor => ctor.GetParameters().Count());
//#else
return type.GetConstructors().OrderByDescending(ctor => ctor.GetParameters().Count());
//#endif
}
private object ConstructType(Type requestedType, Type implementationType, ResolveOptions options)
{
return ConstructType(requestedType, implementationType, null, NamedParameterOverloads.Default, options);
}
private object ConstructType(Type requestedType, Type implementationType, ConstructorInfo constructor, ResolveOptions options)
{
return ConstructType(requestedType, implementationType, constructor, NamedParameterOverloads.Default, options);
}
private object ConstructType(Type requestedType, Type implementationType, NamedParameterOverloads parameters, ResolveOptions options)
{
return ConstructType(requestedType, implementationType, null, parameters, options);
}
private object ConstructType(Type requestedType, Type implementationType, ConstructorInfo constructor, NamedParameterOverloads parameters, ResolveOptions options)
{
var typeToConstruct = implementationType;
#if RESOLVE_OPEN_GENERICS
if (implementationType.IsGenericTypeDefinition())
{
if (requestedType == null || !requestedType.IsGenericType() || !requestedType.GetGenericArguments().Any())
throw new TinyIoCResolutionException(typeToConstruct);
typeToConstruct = typeToConstruct.MakeGenericType(requestedType.GetGenericArguments());
}
#endif
if (constructor == null)
{
// Try and get the best constructor that we can construct
// if we can't construct any then get the constructor
// with the least number of parameters so we can throw a meaningful
// resolve exception
constructor = GetBestConstructor(typeToConstruct, parameters, options) ?? GetTypeConstructors(typeToConstruct).LastOrDefault();
}
if (constructor == null)
throw new TinyIoCResolutionException(typeToConstruct);
var ctorParams = constructor.GetParameters();
object[] args = new object[ctorParams.Count()];
for (int parameterIndex = 0; parameterIndex < ctorParams.Count(); parameterIndex++)
{
var currentParam = ctorParams[parameterIndex];
try
{
if (ctorParams[parameterIndex].ParameterType == typeof(Logger))
{
args[parameterIndex] = LogManager.GetLogger(implementationType.Name);
}
else
{
args[parameterIndex] = parameters.ContainsKey(currentParam.Name) ?
parameters[currentParam.Name] :
ResolveInternal(
new TypeRegistration(currentParam.ParameterType),
NamedParameterOverloads.Default,
options);
}
}
catch (TinyIoCResolutionException ex)
{
// If a constructor parameter can't be resolved
// it will throw, so wrap it and throw that this can't
// be resolved.
throw new TinyIoCResolutionException(typeToConstruct, ex);
}
catch (Exception ex)
{
throw new TinyIoCResolutionException(typeToConstruct, ex);
}
}
try
{
#if USE_OBJECT_CONSTRUCTOR
var constructionDelegate = CreateObjectConstructionDelegateWithCache(constructor);
return constructionDelegate.Invoke(args);
#else
return constructor.Invoke(args);
#endif
}
catch (Exception ex)
{
throw new TinyIoCResolutionException(typeToConstruct, ex);
}
}
#if USE_OBJECT_CONSTRUCTOR
private static ObjectConstructor CreateObjectConstructionDelegateWithCache(ConstructorInfo constructor)
{
ObjectConstructor objectConstructor;
if (_ObjectConstructorCache.TryGetValue(constructor, out objectConstructor))
return objectConstructor;
// We could lock the cache here, but there's no real side
// effect to two threads creating the same ObjectConstructor
// at the same time, compared to the cost of a lock for
// every creation.
var constructorParams = constructor.GetParameters();
var lambdaParams = Expression.Parameter(typeof(object[]), "parameters");
var newParams = new Expression[constructorParams.Length];
for (int i = 0; i < constructorParams.Length; i++)
{
var paramsParameter = Expression.ArrayIndex(lambdaParams, Expression.Constant(i));
newParams[i] = Expression.Convert(paramsParameter, constructorParams[i].ParameterType);
}
var newExpression = Expression.New(constructor, newParams);
var constructionLambda = Expression.Lambda(typeof(ObjectConstructor), newExpression, lambdaParams);
objectConstructor = (ObjectConstructor)constructionLambda.Compile();
_ObjectConstructorCache[constructor] = objectConstructor;
return objectConstructor;
}
#endif
private void BuildUpInternal(object input, ResolveOptions resolveOptions)
{
//#if NETFX_CORE
// var properties = from property in input.GetType().GetTypeInfo().DeclaredProperties
// where (property.GetMethod != null) && (property.SetMethod != null) && !property.PropertyType.GetTypeInfo().IsValueType
// select property;
//#else
var properties = from property in input.GetType().GetProperties()
where (property.GetGetMethod() != null) && (property.GetSetMethod() != null) && !property.PropertyType.IsValueType()
select property;
//#endif
foreach (var property in properties)
{
if (property.GetValue(input, null) == null)
{
try
{
property.SetValue(input, ResolveInternal(new TypeRegistration(property.PropertyType), NamedParameterOverloads.Default, resolveOptions), null);
}
catch (TinyIoCResolutionException)
{
// Catch any resolution errors and ignore them
}
}
}
}
private IEnumerable<TypeRegistration> GetParentRegistrationsForType(Type resolveType)
{
if (_Parent == null)
return new TypeRegistration[] { };
var registrations = _Parent._RegisteredTypes.Keys.Where(tr => tr.Type == resolveType);
return registrations.Concat(_Parent.GetParentRegistrationsForType(resolveType));
}
private IEnumerable<object> ResolveAllInternal(Type resolveType, bool includeUnnamed)
{
var registrations = _RegisteredTypes.Keys.Where(tr => tr.Type == resolveType).Concat(GetParentRegistrationsForType(resolveType));
if (!includeUnnamed)
registrations = registrations.Where(tr => tr.Name != string.Empty);
return registrations.Select(registration => this.ResolveInternal(registration, NamedParameterOverloads.Default, ResolveOptions.Default));
}
private static bool IsValidAssignment(Type registerType, Type registerImplementation)
{
//#if NETFX_CORE
// var registerTypeDef = registerType.GetTypeInfo();
// var registerImplementationDef = registerImplementation.GetTypeInfo();
// if (!registerTypeDef.IsGenericTypeDefinition)
// {
// if (!registerTypeDef.IsAssignableFrom(registerImplementationDef))
// return false;
// }
// else
// {
// if (registerTypeDef.IsInterface())
// {
// if (!registerImplementationDef.ImplementedInterfaces.Any(t => t.GetTypeInfo().Name == registerTypeDef.Name))
// return false;
// }
// else if (registerTypeDef.IsAbstract() && registerImplementationDef.BaseType() != registerType)
// {
// return false;
// }
// }
//#else
if (!registerType.IsGenericTypeDefinition())
{
if (!registerType.IsAssignableFrom(registerImplementation))
return false;
}
else
{
if (registerType.IsInterface())
{
if (!registerImplementation.FindInterfaces((t, o) => t.Name == registerType.Name, null).Any())
return false;
}
else if (registerType.IsAbstract() && registerImplementation.BaseType() != registerType)
{
return false;
}
}
//#endif
return true;
}
#endregion
#region IDisposable Members
bool disposed = false;
public void Dispose()
{
if (!disposed)
{
disposed = true;
_RegisteredTypes.Dispose();
GC.SuppressFinalize(this);
}
}
#endregion
}
}
// reverse shim for WinRT SR changes...
#if !NETFX_CORE
namespace System.Reflection
{
public static class ReverseTypeExtender
{
public static bool IsClass(this Type type)
{
return type.IsClass;
}
public static bool IsAbstract(this Type type)
{
return type.IsAbstract;
}
public static bool IsInterface(this Type type)
{
return type.IsInterface;
}
public static bool IsPrimitive(this Type type)
{
return type.IsPrimitive;
}
public static bool IsValueType(this Type type)
{
return type.IsValueType;
}
public static bool IsGenericType(this Type type)
{
return type.IsGenericType;
}
public static bool IsGenericParameter(this Type type)
{
return type.IsGenericParameter;
}
public static bool IsGenericTypeDefinition(this Type type)
{
return type.IsGenericTypeDefinition;
}
public static Type BaseType(this Type type)
{
return type.BaseType;
}
public static Assembly Assembly(this Type type)
{
return type.Assembly;
}
}
}
#endif