3892 lines
161 KiB
C#
3892 lines
161 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
|
|
{
|
|
get
|
|
{
|
|
return _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
|
|
{
|
|
get
|
|
{
|
|
return _Default;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Preconfigured option for attempting resolution of unregistered types and failing on named resolution if name not found
|
|
/// </summary>
|
|
public static ResolveOptions FailNameNotFoundOnly
|
|
{
|
|
get
|
|
{
|
|
return _FailNameNotFoundOnly;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Preconfigured option for failing on resolving unregistered types and on named resolution if name not found
|
|
/// </summary>
|
|
public static ResolveOptions FailUnregisteredAndNameNotFound
|
|
{
|
|
get
|
|
{
|
|
return _FailUnregisteredAndNameNotFound;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Preconfigured option for failing on resolving unregistered types, but attempting unnamed resolution if name not found
|
|
/// </summary>
|
|
public static ResolveOptions FailUnregisteredOnly
|
|
{
|
|
get
|
|
{
|
|
return _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 { get { return 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 { get { return 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
|
|
{
|
|
get
|
|
{
|
|
return 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
|
|
{
|
|
get
|
|
{
|
|
return 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 { get { return true; } }
|
|
|
|
public override Type CreatesType { get { return 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
|
|
{
|
|
get
|
|
{
|
|
return new WeakDelegateFactory(this.registerType, _factory);
|
|
}
|
|
}
|
|
|
|
public override ObjectFactoryBase StrongReferenceVariant
|
|
{
|
|
get
|
|
{
|
|
return 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 { get { return true; } }
|
|
|
|
public override Type CreatesType { get { return 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
|
|
{
|
|
get
|
|
{
|
|
return 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 { get { return 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
|
|
{
|
|
get { return this.registerImplementation; }
|
|
}
|
|
|
|
public override object GetObject(Type requestedType, TinyIoCContainer container, NamedParameterOverloads parameters, ResolveOptions options)
|
|
{
|
|
return _instance;
|
|
}
|
|
|
|
public override ObjectFactoryBase MultiInstanceVariant
|
|
{
|
|
get { return new MultiInstanceFactory(this.registerType, this.registerImplementation); }
|
|
}
|
|
|
|
public override ObjectFactoryBase WeakReferenceVariant
|
|
{
|
|
get
|
|
{
|
|
return new WeakInstanceFactory(this.registerType, this.registerImplementation, this._instance);
|
|
}
|
|
}
|
|
|
|
public override ObjectFactoryBase StrongReferenceVariant
|
|
{
|
|
get
|
|
{
|
|
return 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
|
|
{
|
|
get { return 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
|
|
{
|
|
get
|
|
{
|
|
return new MultiInstanceFactory(this.registerType, this.registerImplementation);
|
|
}
|
|
}
|
|
|
|
public override ObjectFactoryBase WeakReferenceVariant
|
|
{
|
|
get
|
|
{
|
|
return 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
|
|
{
|
|
get { return 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
|
|
{
|
|
get
|
|
{
|
|
return this;
|
|
}
|
|
}
|
|
|
|
public override ObjectFactoryBase GetCustomObjectLifetimeVariant(ITinyIoCObjectLifetimeProvider lifetimeProvider, string errorString)
|
|
{
|
|
return new CustomObjectLifetimeFactory(this.registerType, this.registerImplementation, lifetimeProvider, errorString);
|
|
}
|
|
|
|
public override ObjectFactoryBase MultiInstanceVariant
|
|
{
|
|
get
|
|
{
|
|
return 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
|
|
{
|
|
get { return 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
|
|
{
|
|
get
|
|
{
|
|
return _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 |