//=============================================================================== // 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 : IDisposable { private readonly ReaderWriterLockSlim _padlock = new ReaderWriterLockSlim(); private readonly Dictionary _Dictionary = new Dictionary(); 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 Keys { get { _padlock.EnterReadLock(); try { return new List(_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 : IDisposable { private readonly object _Padlock = new object(); private readonly Dictionary _Dictionary = new Dictionary(); 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 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 _genericMethodCache; static TypeExtensions() { _genericMethodCache = new SafeDictionary(); } //#if NETFX_CORE // /// // /// Gets a generic method from a type given the method name, generic types and parameter types // /// // /// Source type // /// Name of the method // /// Generic types to use to make the method generic // /// Method parameters // /// MethodInfo or null if no matches found // /// // /// // 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 /// /// Gets a generic method from a type given the method name, binding flags, generic types and parameter types /// /// Source type /// Binding flags /// Name of the method /// Generic types to use to make the method generic /// Method parameters /// MethodInfo or null if no matches found /// /// 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... #if NETFX_CORE internal static class ListExtender { internal static void ForEach(this List list, Action 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 types) : base(string.Format(ERROR_TEXT, registerType, GetTypesString(types))) { } public TinyIoCAutoRegistrationException(Type registerType, IEnumerable types, Exception innerException) : base(string.Format(ERROR_TEXT, registerType, GetTypesString(types)), innerException) { } private static string GetTypesString(IEnumerable types) { var typeNames = from type in types select type.FullName; return string.Join(",", typeNames.ToArray()); } } #endregion #region Public Setup / Settings Classes /// /// Name/Value pairs for specifying "user" parameters when resolving /// public sealed class NamedParameterOverloads : Dictionary { public static NamedParameterOverloads FromIDictionary(IDictionary data) { return data as NamedParameterOverloads ?? new NamedParameterOverloads(data); } public NamedParameterOverloads() { } public NamedParameterOverloads(IDictionary data) : base(data) { } private static readonly NamedParameterOverloads _Default = new NamedParameterOverloads(); public static NamedParameterOverloads Default => _Default; } public enum UnregisteredResolutionActions { /// /// Attempt to resolve type, even if the type isn't registered. /// /// Registered types/options will always take precedence. /// AttemptResolve, /// /// Fail resolution if type not explicitly registered /// Fail, /// /// 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. /// GenericsOnly } public enum NamedResolutionFailureActions { AttemptUnnamedResolution, Fail } public enum DuplicateImplementationActions { RegisterSingle, RegisterMultiple, Fail } /// /// Resolution settings /// 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; } } /// /// Gets the default options (attempt resolution of unregistered types, fail on named resolution if name not found) /// public static ResolveOptions Default => _Default; /// /// Preconfigured option for attempting resolution of unregistered types and failing on named resolution if name not found /// public static ResolveOptions FailNameNotFoundOnly => _FailNameNotFoundOnly; /// /// Preconfigured option for failing on resolving unregistered types and on named resolution if name not found /// public static ResolveOptions FailUnregisteredAndNameNotFound => _FailUnregisteredAndNameNotFound; /// /// Preconfigured option for failing on resolving unregistered types, but attempting unnamed resolution if name not found /// public static ResolveOptions FailUnregisteredOnly => _FailUnregisteredOnly; } #endregion public sealed partial class TinyIoCContainer : IDisposable { #region Fake NETFX_CORE Classes #if NETFX_CORE private sealed class MethodAccessException : Exception { } private sealed class AppDomain { public static AppDomain CurrentDomain { get; private set; } static AppDomain() { CurrentDomain = new AppDomain(); } // @mbrit - 2012-05-30 - in WinRT, this should be done async... public async Task> GetAssembliesAsync() { var folder = Windows.ApplicationModel.Package.Current.InstalledLocation; List assemblies = new List(); 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 /// /// Registration options for "fluent" API /// public sealed class RegisterOptions { private TinyIoCContainer _Container; private TypeRegistration _Registration; public RegisterOptions(TinyIoCContainer container, TypeRegistration registration) { _Container = container; _Registration = registration; } /// /// Make registration a singleton (single instance) if possible /// /// RegisterOptions /// public RegisterOptions AsSingleton() { var currentFactory = _Container.GetCurrentFactory(_Registration); if (currentFactory == null) throw new TinyIoCRegistrationException(_Registration.Type, "singleton"); return _Container.AddUpdateRegistration(_Registration, currentFactory.SingletonVariant); } /// /// Make registration multi-instance if possible /// /// RegisterOptions /// public RegisterOptions AsMultiInstance() { var currentFactory = _Container.GetCurrentFactory(_Registration); if (currentFactory == null) throw new TinyIoCRegistrationException(_Registration.Type, "multi-instance"); return _Container.AddUpdateRegistration(_Registration, currentFactory.MultiInstanceVariant); } /// /// Make registration hold a weak reference if possible /// /// RegisterOptions /// public RegisterOptions WithWeakReference() { var currentFactory = _Container.GetCurrentFactory(_Registration); if (currentFactory == null) throw new TinyIoCRegistrationException(_Registration.Type, "weak reference"); return _Container.AddUpdateRegistration(_Registration, currentFactory.WeakReferenceVariant); } /// /// Make registration hold a strong reference if possible /// /// RegisterOptions /// 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(Expression> 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 /// /// Switches to a custom lifetime manager factory if possible. /// /// Usually used for RegisterOptions "To*" extension methods such as the ASP.Net per-request one. /// /// RegisterOptions instance /// Custom lifetime manager /// Error string to display if switch fails /// RegisterOptions 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)); } } /// /// Registration options for "fluent" API when registering multiple implementations /// public sealed class MultiRegisterOptions { private IEnumerable _RegisterOptions; /// /// Initializes a new instance of the MultiRegisterOptions class. /// /// Registration options public MultiRegisterOptions(IEnumerable registerOptions) { _RegisterOptions = registerOptions; } /// /// Make registration a singleton (single instance) if possible /// /// RegisterOptions /// public MultiRegisterOptions AsSingleton() { _RegisterOptions = ExecuteOnAllRegisterOptions(ro => ro.AsSingleton()); return this; } /// /// Make registration multi-instance if possible /// /// MultiRegisterOptions /// public MultiRegisterOptions AsMultiInstance() { _RegisterOptions = ExecuteOnAllRegisterOptions(ro => ro.AsMultiInstance()); return this; } private IEnumerable ExecuteOnAllRegisterOptions(Func action) { var newRegisterOptions = new List(); 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 /// /// 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. /// 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 } /// /// 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. /// /// Predicate to determine if a particular type should be registered public void AutoRegister(Func 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 } /// /// Attempt to automatically register all non-generic classes and interfaces in the current app domain. /// /// What action to take when encountering duplicate implementations of an interface/base class. /// 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 } /// /// 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. /// /// What action to take when encountering duplicate implementations of an interface/base class. /// Predicate to determine if a particular type should be registered /// public void AutoRegister(DuplicateImplementationActions duplicateAction, Func registrationPredicate) { #if APPDOMAIN_GETASSEMBLIES AutoRegisterInternal(AppDomain.CurrentDomain.GetAssemblies().Where(a => !IsIgnoredAssembly(a)), duplicateAction, registrationPredicate); #else AutoRegisterInternal(new Assembly[] { this.GetType().Assembly() }, ignoreDuplicateImplementations, registrationPredicate); #endif } /// /// 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. /// /// Assemblies to process public void AutoRegister(IEnumerable assemblies) { AutoRegisterInternal(assemblies, DuplicateImplementationActions.RegisterSingle, null); } /// /// 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. /// /// Assemblies to process /// Predicate to determine if a particular type should be registered public void AutoRegister(IEnumerable assemblies, Func registrationPredicate) { AutoRegisterInternal(assemblies, DuplicateImplementationActions.RegisterSingle, registrationPredicate); } /// /// Attempt to automatically register all non-generic classes and interfaces in the specified assemblies /// /// Assemblies to process /// What action to take when encountering duplicate implementations of an interface/base class. /// public void AutoRegister(IEnumerable assemblies, DuplicateImplementationActions duplicateAction) { AutoRegisterInternal(assemblies, duplicateAction, null); } /// /// 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. /// /// Assemblies to process /// What action to take when encountering duplicate implementations of an interface/base class. /// Predicate to determine if a particular type should be registered /// public void AutoRegister(IEnumerable assemblies, DuplicateImplementationActions duplicateAction, Func registrationPredicate) { AutoRegisterInternal(assemblies, duplicateAction, registrationPredicate); } /// /// Creates/replaces a container class registration with default options. /// /// Type to register /// RegisterOptions for fluent API public RegisterOptions Register(Type registerType) { return RegisterInternal(registerType, string.Empty, GetDefaultObjectFactory(registerType, registerType)); } /// /// Creates/replaces a named container class registration with default options. /// /// Type to register /// Name of registration /// RegisterOptions for fluent API public RegisterOptions Register(Type registerType, string name) { return RegisterInternal(registerType, name, GetDefaultObjectFactory(registerType, registerType)); } /// /// Creates/replaces a container class registration with a given implementation and default options. /// /// Type to register /// Type to instantiate that implements RegisterType /// RegisterOptions for fluent API public RegisterOptions Register(Type registerType, Type registerImplementation) { return this.RegisterInternal(registerType, string.Empty, GetDefaultObjectFactory(registerType, registerImplementation)); } /// /// Creates/replaces a named container class registration with a given implementation and default options. /// /// Type to register /// Type to instantiate that implements RegisterType /// Name of registration /// RegisterOptions for fluent API public RegisterOptions Register(Type registerType, Type registerImplementation, string name) { return this.RegisterInternal(registerType, name, GetDefaultObjectFactory(registerType, registerImplementation)); } /// /// Creates/replaces a container class registration with a specific, strong referenced, instance. /// /// Type to register /// Instance of RegisterType to register /// RegisterOptions for fluent API public RegisterOptions Register(Type registerType, object instance) { return RegisterInternal(registerType, string.Empty, new InstanceFactory(registerType, registerType, instance)); } /// /// Creates/replaces a named container class registration with a specific, strong referenced, instance. /// /// Type to register /// Instance of RegisterType to register /// Name of registration /// RegisterOptions for fluent API public RegisterOptions Register(Type registerType, object instance, string name) { return RegisterInternal(registerType, name, new InstanceFactory(registerType, registerType, instance)); } /// /// Creates/replaces a container class registration with a specific, strong referenced, instance. /// /// Type to register /// Type of instance to register that implements RegisterType /// Instance of RegisterImplementation to register /// RegisterOptions for fluent API public RegisterOptions Register(Type registerType, Type registerImplementation, object instance) { return RegisterInternal(registerType, string.Empty, new InstanceFactory(registerType, registerImplementation, instance)); } /// /// Creates/replaces a named container class registration with a specific, strong referenced, instance. /// /// Type to register /// Type of instance to register that implements RegisterType /// Instance of RegisterImplementation to register /// Name of registration /// RegisterOptions for fluent API public RegisterOptions Register(Type registerType, Type registerImplementation, object instance, string name) { return RegisterInternal(registerType, name, new InstanceFactory(registerType, registerImplementation, instance)); } /// /// Creates/replaces a container class registration with a user specified factory /// /// Type to register /// Factory/lambda that returns an instance of RegisterType /// RegisterOptions for fluent API public RegisterOptions Register(Type registerType, Func factory) { return RegisterInternal(registerType, string.Empty, new DelegateFactory(registerType, factory)); } /// /// Creates/replaces a container class registration with a user specified factory /// /// Type to register /// Factory/lambda that returns an instance of RegisterType /// Name of registation /// RegisterOptions for fluent API public RegisterOptions Register(Type registerType, Func factory, string name) { return RegisterInternal(registerType, name, new DelegateFactory(registerType, factory)); } /// /// Creates/replaces a container class registration with default options. /// /// Type to register /// RegisterOptions for fluent API public RegisterOptions Register() where RegisterType : class { return this.Register(typeof(RegisterType)); } /// /// Creates/replaces a named container class registration with default options. /// /// Type to register /// Name of registration /// RegisterOptions for fluent API public RegisterOptions Register(string name) where RegisterType : class { return this.Register(typeof(RegisterType), name); } /// /// Creates/replaces a container class registration with a given implementation and default options. /// /// Type to register /// Type to instantiate that implements RegisterType /// RegisterOptions for fluent API public RegisterOptions Register() where RegisterType : class where RegisterImplementation : class, RegisterType { return this.Register(typeof(RegisterType), typeof(RegisterImplementation)); } /// /// Creates/replaces a named container class registration with a given implementation and default options. /// /// Type to register /// Type to instantiate that implements RegisterType /// Name of registration /// RegisterOptions for fluent API public RegisterOptions Register(string name) where RegisterType : class where RegisterImplementation : class, RegisterType { return this.Register(typeof(RegisterType), typeof(RegisterImplementation), name); } /// /// Creates/replaces a container class registration with a specific, strong referenced, instance. /// /// Type to register /// Instance of RegisterType to register /// RegisterOptions for fluent API public RegisterOptions Register(RegisterType instance) where RegisterType : class { return this.Register(typeof(RegisterType), instance); } /// /// Creates/replaces a named container class registration with a specific, strong referenced, instance. /// /// Type to register /// Instance of RegisterType to register /// Name of registration /// RegisterOptions for fluent API public RegisterOptions Register(RegisterType instance, string name) where RegisterType : class { return this.Register(typeof(RegisterType), instance, name); } /// /// Creates/replaces a container class registration with a specific, strong referenced, instance. /// /// Type to register /// Type of instance to register that implements RegisterType /// Instance of RegisterImplementation to register /// RegisterOptions for fluent API public RegisterOptions Register(RegisterImplementation instance) where RegisterType : class where RegisterImplementation : class, RegisterType { return this.Register(typeof(RegisterType), typeof(RegisterImplementation), instance); } /// /// Creates/replaces a named container class registration with a specific, strong referenced, instance. /// /// Type to register /// Type of instance to register that implements RegisterType /// Instance of RegisterImplementation to register /// Name of registration /// RegisterOptions for fluent API public RegisterOptions Register(RegisterImplementation instance, string name) where RegisterType : class where RegisterImplementation : class, RegisterType { return this.Register(typeof(RegisterType), typeof(RegisterImplementation), instance, name); } /// /// Creates/replaces a container class registration with a user specified factory /// /// Type to register /// Factory/lambda that returns an instance of RegisterType /// RegisterOptions for fluent API public RegisterOptions Register(Func factory) where RegisterType : class { if (factory == null) { throw new ArgumentNullException("factory"); } return this.Register(typeof(RegisterType), (c, o) => factory(c, o)); } /// /// Creates/replaces a named container class registration with a user specified factory /// /// Type to register /// Factory/lambda that returns an instance of RegisterType /// Name of registation /// RegisterOptions for fluent API public RegisterOptions Register(Func factory, string name) where RegisterType : class { if (factory == null) { throw new ArgumentNullException("factory"); } return this.Register(typeof(RegisterType), (c, o) => factory(c, o), name); } /// /// Register multiple implementations of a type. /// /// Internally this registers each implementation using the full name of the class as its registration name. /// /// Type that each implementation implements /// Types that implement RegisterType /// MultiRegisterOptions for the fluent API public MultiRegisterOptions RegisterMultiple(IEnumerable implementationTypes) { return RegisterMultiple(typeof(RegisterType), implementationTypes); } /// /// Register multiple implementations of a type. /// /// Internally this registers each implementation using the full name of the class as its registration name. /// /// Type that each implementation implements /// Types that implement RegisterType /// MultiRegisterOptions for the fluent API public MultiRegisterOptions RegisterMultiple(Type registrationType, IEnumerable 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(); foreach (var type in implementationTypes) { registerOptions.Add(Register(registrationType, type, type.FullName)); } return new MultiRegisterOptions(registerOptions); } #endregion #region Resolution /// /// Attempts to resolve a type using default options. /// /// Type to resolve /// Instance of type /// Unable to resolve the type. public object Resolve(Type resolveType) { return ResolveInternal(new TypeRegistration(resolveType), NamedParameterOverloads.Default, ResolveOptions.Default); } /// /// Attempts to resolve a type using specified options. /// /// Type to resolve /// Resolution options /// Instance of type /// Unable to resolve the type. public object Resolve(Type resolveType, ResolveOptions options) { return ResolveInternal(new TypeRegistration(resolveType), NamedParameterOverloads.Default, options); } /// /// 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. /// /// Type to resolve /// Name of registration /// Instance of type /// Unable to resolve the type. public object Resolve(Type resolveType, string name) { return ResolveInternal(new TypeRegistration(resolveType, name), NamedParameterOverloads.Default, ResolveOptions.Default); } /// /// 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. /// /// Type to resolve /// Name of registration /// Resolution options /// Instance of type /// Unable to resolve the type. public object Resolve(Type resolveType, string name, ResolveOptions options) { return ResolveInternal(new TypeRegistration(resolveType, name), NamedParameterOverloads.Default, options); } /// /// 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. /// /// Type to resolve /// User specified constructor parameters /// Instance of type /// Unable to resolve the type. public object Resolve(Type resolveType, NamedParameterOverloads parameters) { return ResolveInternal(new TypeRegistration(resolveType), parameters, ResolveOptions.Default); } /// /// 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. /// /// Type to resolve /// User specified constructor parameters /// Resolution options /// Instance of type /// Unable to resolve the type. public object Resolve(Type resolveType, NamedParameterOverloads parameters, ResolveOptions options) { return ResolveInternal(new TypeRegistration(resolveType), parameters, options); } /// /// 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. /// /// Type to resolve /// User specified constructor parameters /// Name of registration /// Instance of type /// Unable to resolve the type. public object Resolve(Type resolveType, string name, NamedParameterOverloads parameters) { return ResolveInternal(new TypeRegistration(resolveType, name), parameters, ResolveOptions.Default); } /// /// 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. /// /// Type to resolve /// Name of registration /// User specified constructor parameters /// Resolution options /// Instance of type /// Unable to resolve the type. public object Resolve(Type resolveType, string name, NamedParameterOverloads parameters, ResolveOptions options) { return ResolveInternal(new TypeRegistration(resolveType, name), parameters, options); } /// /// Attempts to resolve a type using default options. /// /// Type to resolve /// Instance of type /// Unable to resolve the type. public ResolveType Resolve() where ResolveType : class { return (ResolveType)Resolve(typeof(ResolveType)); } /// /// Attempts to resolve a type using specified options. /// /// Type to resolve /// Resolution options /// Instance of type /// Unable to resolve the type. public ResolveType Resolve(ResolveOptions options) where ResolveType : class { return (ResolveType)Resolve(typeof(ResolveType), options); } /// /// 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. /// /// Type to resolve /// Name of registration /// Instance of type /// Unable to resolve the type. public ResolveType Resolve(string name) where ResolveType : class { return (ResolveType)Resolve(typeof(ResolveType), name); } /// /// 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. /// /// Type to resolve /// Name of registration /// Resolution options /// Instance of type /// Unable to resolve the type. public ResolveType Resolve(string name, ResolveOptions options) where ResolveType : class { return (ResolveType)Resolve(typeof(ResolveType), name, options); } /// /// 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. /// /// Type to resolve /// User specified constructor parameters /// Instance of type /// Unable to resolve the type. public ResolveType Resolve(NamedParameterOverloads parameters) where ResolveType : class { return (ResolveType)Resolve(typeof(ResolveType), parameters); } /// /// 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. /// /// Type to resolve /// User specified constructor parameters /// Resolution options /// Instance of type /// Unable to resolve the type. public ResolveType Resolve(NamedParameterOverloads parameters, ResolveOptions options) where ResolveType : class { return (ResolveType)Resolve(typeof(ResolveType), parameters, options); } /// /// 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. /// /// Type to resolve /// User specified constructor parameters /// Name of registration /// Instance of type /// Unable to resolve the type. public ResolveType Resolve(string name, NamedParameterOverloads parameters) where ResolveType : class { return (ResolveType)Resolve(typeof(ResolveType), name, parameters); } /// /// 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. /// /// Type to resolve /// Name of registration /// User specified constructor parameters /// Resolution options /// Instance of type /// Unable to resolve the type. public ResolveType Resolve(string name, NamedParameterOverloads parameters, ResolveOptions options) where ResolveType : class { return (ResolveType)Resolve(typeof(ResolveType), name, parameters, options); } /// /// 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. /// /// Type to resolve /// Name of registration /// Bool indicating whether the type can be resolved public bool CanResolve(Type resolveType) { return CanResolveInternal(new TypeRegistration(resolveType), NamedParameterOverloads.Default, ResolveOptions.Default); } /// /// 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. /// /// Type to resolve /// Bool indicating whether the type can be resolved private bool CanResolve(Type resolveType, string name) { return CanResolveInternal(new TypeRegistration(resolveType, name), NamedParameterOverloads.Default, ResolveOptions.Default); } /// /// 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. /// /// Type to resolve /// Name of registration /// Resolution options /// Bool indicating whether the type can be resolved public bool CanResolve(Type resolveType, ResolveOptions options) { return CanResolveInternal(new TypeRegistration(resolveType), NamedParameterOverloads.Default, options); } /// /// 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. /// /// Type to resolve /// Name of registration /// Resolution options /// Bool indicating whether the type can be resolved public bool CanResolve(Type resolveType, string name, ResolveOptions options) { return CanResolveInternal(new TypeRegistration(resolveType, name), NamedParameterOverloads.Default, options); } /// /// 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. /// /// Type to resolve /// User supplied named parameter overloads /// Bool indicating whether the type can be resolved public bool CanResolve(Type resolveType, NamedParameterOverloads parameters) { return CanResolveInternal(new TypeRegistration(resolveType), parameters, ResolveOptions.Default); } /// /// 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. /// /// Type to resolve /// Name of registration /// User supplied named parameter overloads /// Bool indicating whether the type can be resolved public bool CanResolve(Type resolveType, string name, NamedParameterOverloads parameters) { return CanResolveInternal(new TypeRegistration(resolveType, name), parameters, ResolveOptions.Default); } /// /// 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. /// /// Type to resolve /// User supplied named parameter overloads /// Resolution options /// Bool indicating whether the type can be resolved public bool CanResolve(Type resolveType, NamedParameterOverloads parameters, ResolveOptions options) { return CanResolveInternal(new TypeRegistration(resolveType), parameters, options); } /// /// 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. /// /// Type to resolve /// Name of registration /// User supplied named parameter overloads /// Resolution options /// Bool indicating whether the type can be resolved public bool CanResolve(Type resolveType, string name, NamedParameterOverloads parameters, ResolveOptions options) { return CanResolveInternal(new TypeRegistration(resolveType, name), parameters, options); } /// /// 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. /// /// Type to resolve /// Name of registration /// Bool indicating whether the type can be resolved public bool CanResolve() where ResolveType : class { return CanResolve(typeof(ResolveType)); } /// /// 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. /// /// Type to resolve /// Bool indicating whether the type can be resolved public bool CanResolve(string name) where ResolveType : class { return CanResolve(typeof(ResolveType), name); } /// /// 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. /// /// Type to resolve /// Name of registration /// Resolution options /// Bool indicating whether the type can be resolved public bool CanResolve(ResolveOptions options) where ResolveType : class { return CanResolve(typeof(ResolveType), options); } /// /// 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. /// /// Type to resolve /// Name of registration /// Resolution options /// Bool indicating whether the type can be resolved public bool CanResolve(string name, ResolveOptions options) where ResolveType : class { return CanResolve(typeof(ResolveType), name, options); } /// /// 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. /// /// Type to resolve /// User supplied named parameter overloads /// Bool indicating whether the type can be resolved public bool CanResolve(NamedParameterOverloads parameters) where ResolveType : class { return CanResolve(typeof(ResolveType), parameters); } /// /// 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. /// /// Type to resolve /// Name of registration /// User supplied named parameter overloads /// Bool indicating whether the type can be resolved public bool CanResolve(string name, NamedParameterOverloads parameters) where ResolveType : class { return CanResolve(typeof(ResolveType), name, parameters); } /// /// 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. /// /// Type to resolve /// User supplied named parameter overloads /// Resolution options /// Bool indicating whether the type can be resolved public bool CanResolve(NamedParameterOverloads parameters, ResolveOptions options) where ResolveType : class { return CanResolve(typeof(ResolveType), parameters, options); } /// /// 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. /// /// Type to resolve /// Name of registration /// User supplied named parameter overloads /// Resolution options /// Bool indicating whether the type can be resolved public bool CanResolve(string name, NamedParameterOverloads parameters, ResolveOptions options) where ResolveType : class { return CanResolve(typeof(ResolveType), name, parameters, options); } /// /// Attemps to resolve a type using the default options /// /// Type to resolve /// Resolved type or default if resolve fails /// True if resolved sucessfully, false otherwise public bool TryResolve(Type resolveType, out object resolvedType) { try { resolvedType = Resolve(resolveType); return true; } catch (TinyIoCResolutionException) { resolvedType = null; return false; } } /// /// Attemps to resolve a type using the given options /// /// Type to resolve /// Resolution options /// Resolved type or default if resolve fails /// True if resolved sucessfully, false otherwise public bool TryResolve(Type resolveType, ResolveOptions options, out object resolvedType) { try { resolvedType = Resolve(resolveType, options); return true; } catch (TinyIoCResolutionException) { resolvedType = null; return false; } } /// /// Attemps to resolve a type using the default options and given name /// /// Type to resolve /// Name of registration /// Resolved type or default if resolve fails /// True if resolved sucessfully, false otherwise public bool TryResolve(Type resolveType, string name, out object resolvedType) { try { resolvedType = Resolve(resolveType, name); return true; } catch (TinyIoCResolutionException) { resolvedType = null; return false; } } /// /// Attemps to resolve a type using the given options and name /// /// Type to resolve /// Name of registration /// Resolution options /// Resolved type or default if resolve fails /// True if resolved sucessfully, false otherwise 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; } } /// /// Attemps to resolve a type using the default options and supplied constructor parameters /// /// Type to resolve /// User specified constructor parameters /// Resolved type or default if resolve fails /// True if resolved sucessfully, false otherwise public bool TryResolve(Type resolveType, NamedParameterOverloads parameters, out object resolvedType) { try { resolvedType = Resolve(resolveType, parameters); return true; } catch (TinyIoCResolutionException) { resolvedType = null; return false; } } /// /// Attemps to resolve a type using the default options and supplied name and constructor parameters /// /// Type to resolve /// Name of registration /// User specified constructor parameters /// Resolved type or default if resolve fails /// True if resolved sucessfully, false otherwise 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; } } /// /// Attemps to resolve a type using the supplied options and constructor parameters /// /// Type to resolve /// Name of registration /// User specified constructor parameters /// Resolution options /// Resolved type or default if resolve fails /// True if resolved sucessfully, false otherwise 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; } } /// /// Attemps to resolve a type using the supplied name, options and constructor parameters /// /// Type to resolve /// Name of registration /// User specified constructor parameters /// Resolution options /// Resolved type or default if resolve fails /// True if resolved sucessfully, false otherwise 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; } } /// /// Attemps to resolve a type using the default options /// /// Type to resolve /// Resolved type or default if resolve fails /// True if resolved sucessfully, false otherwise public bool TryResolve(out ResolveType resolvedType) where ResolveType : class { try { resolvedType = Resolve(); return true; } catch (TinyIoCResolutionException) { resolvedType = default(ResolveType); return false; } } /// /// Attemps to resolve a type using the given options /// /// Type to resolve /// Resolution options /// Resolved type or default if resolve fails /// True if resolved sucessfully, false otherwise public bool TryResolve(ResolveOptions options, out ResolveType resolvedType) where ResolveType : class { try { resolvedType = Resolve(options); return true; } catch (TinyIoCResolutionException) { resolvedType = default(ResolveType); return false; } } /// /// Attemps to resolve a type using the default options and given name /// /// Type to resolve /// Name of registration /// Resolved type or default if resolve fails /// True if resolved sucessfully, false otherwise public bool TryResolve(string name, out ResolveType resolvedType) where ResolveType : class { try { resolvedType = Resolve(name); return true; } catch (TinyIoCResolutionException) { resolvedType = default(ResolveType); return false; } } /// /// Attemps to resolve a type using the given options and name /// /// Type to resolve /// Name of registration /// Resolution options /// Resolved type or default if resolve fails /// True if resolved sucessfully, false otherwise public bool TryResolve(string name, ResolveOptions options, out ResolveType resolvedType) where ResolveType : class { try { resolvedType = Resolve(name, options); return true; } catch (TinyIoCResolutionException) { resolvedType = default(ResolveType); return false; } } /// /// Attemps to resolve a type using the default options and supplied constructor parameters /// /// Type to resolve /// User specified constructor parameters /// Resolved type or default if resolve fails /// True if resolved sucessfully, false otherwise public bool TryResolve(NamedParameterOverloads parameters, out ResolveType resolvedType) where ResolveType : class { try { resolvedType = Resolve(parameters); return true; } catch (TinyIoCResolutionException) { resolvedType = default(ResolveType); return false; } } /// /// Attemps to resolve a type using the default options and supplied name and constructor parameters /// /// Type to resolve /// Name of registration /// User specified constructor parameters /// Resolved type or default if resolve fails /// True if resolved sucessfully, false otherwise public bool TryResolve(string name, NamedParameterOverloads parameters, out ResolveType resolvedType) where ResolveType : class { try { resolvedType = Resolve(name, parameters); return true; } catch (TinyIoCResolutionException) { resolvedType = default(ResolveType); return false; } } /// /// Attemps to resolve a type using the supplied options and constructor parameters /// /// Type to resolve /// Name of registration /// User specified constructor parameters /// Resolution options /// Resolved type or default if resolve fails /// True if resolved sucessfully, false otherwise public bool TryResolve(NamedParameterOverloads parameters, ResolveOptions options, out ResolveType resolvedType) where ResolveType : class { try { resolvedType = Resolve(parameters, options); return true; } catch (TinyIoCResolutionException) { resolvedType = default(ResolveType); return false; } } /// /// Attemps to resolve a type using the supplied name, options and constructor parameters /// /// Type to resolve /// Name of registration /// User specified constructor parameters /// Resolution options /// Resolved type or default if resolve fails /// True if resolved sucessfully, false otherwise public bool TryResolve(string name, NamedParameterOverloads parameters, ResolveOptions options, out ResolveType resolvedType) where ResolveType : class { try { resolvedType = Resolve(name, parameters, options); return true; } catch (TinyIoCResolutionException) { resolvedType = default(ResolveType); return false; } } /// /// Returns all registrations of a type /// /// Type to resolveAll /// Whether to include un-named (default) registrations /// IEnumerable public IEnumerable ResolveAll(Type resolveType, bool includeUnnamed) { return ResolveAllInternal(resolveType, includeUnnamed); } /// /// Returns all registrations of a type, both named and unnamed /// /// Type to resolveAll /// IEnumerable public IEnumerable ResolveAll(Type resolveType) { return ResolveAll(resolveType, false); } /// /// Returns all registrations of a type /// /// Type to resolveAll /// Whether to include un-named (default) registrations /// IEnumerable public IEnumerable ResolveAll(bool includeUnnamed) where ResolveType : class { return this.ResolveAll(typeof(ResolveType), includeUnnamed).Cast(); } /// /// Returns all registrations of a type, both named and unnamed /// /// Type to resolveAll /// Whether to include un-named (default) registrations /// IEnumerable public IEnumerable ResolveAll() where ResolveType : class { return ResolveAll(true); } /// /// Attempts to resolve all public property dependencies on the given object. /// /// Object to "build up" public void BuildUp(object input) { BuildUpInternal(input, ResolveOptions.Default); } /// /// Attempts to resolve all public property dependencies on the given object using the given resolve options. /// /// Object to "build up" /// Resolve options to use public void BuildUp(object input, ResolveOptions resolveOptions) { BuildUpInternal(input, resolveOptions); } #endregion #endregion #region Object Factories /// /// Provides custom lifetime management for ASP.Net per-request lifetimes etc. /// public interface ITinyIoCObjectLifetimeProvider { /// /// Gets the stored object if it exists, or null if not /// /// Object instance or null object GetObject(); /// /// Store the object /// /// Object to store void SetObject(object value); /// /// Release the object /// void ReleaseObject(); } private abstract class ObjectFactoryBase { /// /// 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. /// public virtual bool AssumeConstruction => false; /// /// The type the factory instantiates /// public abstract Type CreatesType { get; } /// /// Constructor to use, if specified /// public ConstructorInfo Constructor { get; protected set; } /// /// Create the type /// /// Type user requested to be resolved /// Container that requested the creation /// Any user parameters passed /// /// 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; } } /// /// IObjectFactory that creates new instances of types for each resolution /// private class MultiInstanceFactory : ObjectFactoryBase { private readonly Type registerType; private readonly Type registerImplementation; public override Type CreatesType => this.registerImplementation; public MultiInstanceFactory(Type registerType, Type registerImplementation) { //#if NETFX_CORE // if (registerImplementation.GetTypeInfo().IsAbstract() || registerImplementation.GetTypeInfo().IsInterface()) // throw new TinyIoCRegistrationTypeException(registerImplementation, "MultiInstanceFactory"); //#else if (registerImplementation.IsAbstract() || registerImplementation.IsInterface()) throw new TinyIoCRegistrationTypeException(registerImplementation, "MultiInstanceFactory"); //#endif if (!IsValidAssignment(registerType, registerImplementation)) throw new TinyIoCRegistrationTypeException(registerImplementation, "MultiInstanceFactory"); this.registerType = registerType; this.registerImplementation = registerImplementation; } public override object GetObject(Type requestedType, TinyIoCContainer container, NamedParameterOverloads parameters, ResolveOptions options) { try { return container.ConstructType(requestedType, this.registerImplementation, Constructor, parameters, options); } catch (TinyIoCResolutionException ex) { throw new TinyIoCResolutionException(this.registerType, ex); } } public override ObjectFactoryBase SingletonVariant => new SingletonFactory(this.registerType, this.registerImplementation); public override ObjectFactoryBase GetCustomObjectLifetimeVariant(ITinyIoCObjectLifetimeProvider lifetimeProvider, string errorString) { return new CustomObjectLifetimeFactory(this.registerType, this.registerImplementation, lifetimeProvider, errorString); } public override ObjectFactoryBase MultiInstanceVariant => this; } /// /// IObjectFactory that invokes a specified delegate to construct the object /// private class DelegateFactory : ObjectFactoryBase { private readonly Type registerType; private Func _factory; public override bool AssumeConstruction => true; public override Type CreatesType => this.registerType; public override object GetObject(Type requestedType, TinyIoCContainer container, NamedParameterOverloads parameters, ResolveOptions options) { try { return _factory.Invoke(container, parameters); } catch (Exception ex) { throw new TinyIoCResolutionException(this.registerType, ex); } } public DelegateFactory(Type registerType, Func factory) { if (factory == null) throw new ArgumentNullException("factory"); _factory = factory; this.registerType = registerType; } public override ObjectFactoryBase WeakReferenceVariant => new WeakDelegateFactory(this.registerType, _factory); public override ObjectFactoryBase StrongReferenceVariant => this; public override void SetConstructor(ConstructorInfo constructor) { throw new TinyIoCConstructorResolutionException("Constructor selection is not possible for delegate factory registrations"); } } /// /// IObjectFactory that invokes a specified delegate to construct the object /// Holds the delegate using a weak reference /// private class WeakDelegateFactory : ObjectFactoryBase { private readonly Type registerType; private WeakReference _factory; public override bool AssumeConstruction => true; public override Type CreatesType => this.registerType; public override object GetObject(Type requestedType, TinyIoCContainer container, NamedParameterOverloads parameters, ResolveOptions options) { var factory = _factory.Target as Func; 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 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; if (factory == null) throw new TinyIoCWeakReferenceException(this.registerType); return new DelegateFactory(this.registerType, factory); } } public override ObjectFactoryBase WeakReferenceVariant => this; public override void SetConstructor(ConstructorInfo constructor) { throw new TinyIoCConstructorResolutionException("Constructor selection is not possible for delegate factory registrations"); } } /// /// Stores an particular instance to return for a type /// private class InstanceFactory : ObjectFactoryBase, IDisposable { private readonly Type registerType; private readonly Type registerImplementation; private object _instance; public override bool AssumeConstruction => true; public InstanceFactory(Type registerType, Type registerImplementation, object instance) { if (!IsValidAssignment(registerType, registerImplementation)) throw new TinyIoCRegistrationTypeException(registerImplementation, "InstanceFactory"); this.registerType = registerType; this.registerImplementation = registerImplementation; _instance = instance; } public override Type CreatesType => this.registerImplementation; public override object GetObject(Type requestedType, TinyIoCContainer container, NamedParameterOverloads parameters, ResolveOptions options) { return _instance; } public override ObjectFactoryBase MultiInstanceVariant => new MultiInstanceFactory(this.registerType, this.registerImplementation); public override ObjectFactoryBase WeakReferenceVariant => new WeakInstanceFactory(this.registerType, this.registerImplementation, this._instance); public override ObjectFactoryBase StrongReferenceVariant => this; public override void SetConstructor(ConstructorInfo constructor) { throw new TinyIoCConstructorResolutionException("Constructor selection is not possible for instance factory registrations"); } public void Dispose() { var disposable = _instance as IDisposable; if (disposable != null) disposable.Dispose(); } } /// /// Stores an particular instance to return for a type /// /// Stores the instance with a weak reference /// private class WeakInstanceFactory : ObjectFactoryBase, IDisposable { private readonly Type registerType; private readonly Type registerImplementation; private readonly WeakReference _instance; public WeakInstanceFactory(Type registerType, Type registerImplementation, object instance) { if (!IsValidAssignment(registerType, registerImplementation)) throw new TinyIoCRegistrationTypeException(registerImplementation, "WeakInstanceFactory"); this.registerType = registerType; this.registerImplementation = registerImplementation; _instance = new WeakReference(instance); } public override Type CreatesType => this.registerImplementation; public override object GetObject(Type requestedType, TinyIoCContainer container, NamedParameterOverloads parameters, ResolveOptions options) { var instance = _instance.Target; if (instance == null) throw new TinyIoCWeakReferenceException(this.registerType); return instance; } public override ObjectFactoryBase MultiInstanceVariant => new MultiInstanceFactory(this.registerType, this.registerImplementation); public override ObjectFactoryBase WeakReferenceVariant => this; public override ObjectFactoryBase StrongReferenceVariant { get { var instance = _instance.Target; if (instance == null) throw new TinyIoCWeakReferenceException(this.registerType); return new InstanceFactory(this.registerType, this.registerImplementation, instance); } } public override void SetConstructor(ConstructorInfo constructor) { throw new TinyIoCConstructorResolutionException("Constructor selection is not possible for instance factory registrations"); } public void Dispose() { var disposable = _instance.Target as IDisposable; if (disposable != null) disposable.Dispose(); } } /// /// A factory that lazy instantiates a type and always returns the same instance /// private class SingletonFactory : ObjectFactoryBase, IDisposable { private readonly Type registerType; private readonly Type registerImplementation; private readonly object SingletonLock = new object(); private object _Current; public SingletonFactory(Type registerType, Type registerImplementation) { //#if NETFX_CORE // if (registerImplementation.GetTypeInfo().IsAbstract() || registerImplementation.GetTypeInfo().IsInterface()) //#else if (registerImplementation.IsAbstract() || registerImplementation.IsInterface()) //#endif throw new TinyIoCRegistrationTypeException(registerImplementation, "SingletonFactory"); if (!IsValidAssignment(registerType, registerImplementation)) throw new TinyIoCRegistrationTypeException(registerImplementation, "SingletonFactory"); this.registerType = registerType; this.registerImplementation = registerImplementation; } public override Type CreatesType => this.registerImplementation; public override object GetObject(Type requestedType, TinyIoCContainer container, NamedParameterOverloads parameters, ResolveOptions options) { if (parameters.Count != 0) throw new ArgumentException("Cannot specify parameters for singleton types"); lock (SingletonLock) if (_Current == null) _Current = container.ConstructType(requestedType, this.registerImplementation, Constructor, options); return _Current; } public override ObjectFactoryBase SingletonVariant => this; public override ObjectFactoryBase GetCustomObjectLifetimeVariant(ITinyIoCObjectLifetimeProvider lifetimeProvider, string errorString) { return new CustomObjectLifetimeFactory(this.registerType, this.registerImplementation, lifetimeProvider, errorString); } public override ObjectFactoryBase MultiInstanceVariant => new MultiInstanceFactory(this.registerType, this.registerImplementation); public override ObjectFactoryBase GetFactoryForChildContainer(Type type, TinyIoCContainer parent, TinyIoCContainer child) { // We make sure that the singleton is constructed before the child container takes the factory. // Otherwise the results would vary depending on whether or not the parent container had resolved // the type before the child container does. GetObject(type, parent, NamedParameterOverloads.Default, ResolveOptions.Default); return this; } public void Dispose() { if (this._Current == null) return; var disposable = this._Current as IDisposable; if (disposable != null) disposable.Dispose(); } } /// /// A factory that offloads lifetime to an external lifetime provider /// private class CustomObjectLifetimeFactory : ObjectFactoryBase, IDisposable { private readonly object SingletonLock = new object(); private readonly Type registerType; private readonly Type registerImplementation; private readonly ITinyIoCObjectLifetimeProvider _LifetimeProvider; public CustomObjectLifetimeFactory(Type registerType, Type registerImplementation, ITinyIoCObjectLifetimeProvider lifetimeProvider, string errorMessage) { if (lifetimeProvider == null) throw new ArgumentNullException("lifetimeProvider", "lifetimeProvider is null."); if (!IsValidAssignment(registerType, registerImplementation)) throw new TinyIoCRegistrationTypeException(registerImplementation, "SingletonFactory"); //#if NETFX_CORE // if (registerImplementation.GetTypeInfo().IsAbstract() || registerImplementation.GetTypeInfo().IsInterface()) //#else if (registerImplementation.IsAbstract() || registerImplementation.IsInterface()) //#endif throw new TinyIoCRegistrationTypeException(registerImplementation, errorMessage); this.registerType = registerType; this.registerImplementation = registerImplementation; _LifetimeProvider = lifetimeProvider; } public override Type CreatesType => this.registerImplementation; public override object GetObject(Type requestedType, TinyIoCContainer container, NamedParameterOverloads parameters, ResolveOptions options) { object current; lock (SingletonLock) { current = _LifetimeProvider.GetObject(); if (current == null) { current = container.ConstructType(requestedType, this.registerImplementation, Constructor, options); _LifetimeProvider.SetObject(current); } } return current; } public override ObjectFactoryBase SingletonVariant { get { _LifetimeProvider.ReleaseObject(); return new SingletonFactory(this.registerType, this.registerImplementation); } } public override ObjectFactoryBase MultiInstanceVariant { get { _LifetimeProvider.ReleaseObject(); return new MultiInstanceFactory(this.registerType, this.registerImplementation); } } public override ObjectFactoryBase GetCustomObjectLifetimeVariant(ITinyIoCObjectLifetimeProvider lifetimeProvider, string errorString) { _LifetimeProvider.ReleaseObject(); return new CustomObjectLifetimeFactory(this.registerType, this.registerImplementation, lifetimeProvider, errorString); } public override ObjectFactoryBase GetFactoryForChildContainer(Type type, TinyIoCContainer parent, TinyIoCContainer child) { // We make sure that the singleton is constructed before the child container takes the factory. // Otherwise the results would vary depending on whether or not the parent container had resolved // the type before the child container does. GetObject(type, parent, NamedParameterOverloads.Default, ResolveOptions.Default); return this; } public void Dispose() { _LifetimeProvider.ReleaseObject(); } } #endregion #region Singleton Container private static readonly TinyIoCContainer _Current = new TinyIoCContainer(); static TinyIoCContainer() { } /// /// Lazy created Singleton instance of the container for simple scenarios /// public static TinyIoCContainer Current => _Current; #endregion #region Type Registrations public sealed class TypeRegistration { private int _hashCode; public Type Type { get; private set; } public string Name { get; private set; } public TypeRegistration(Type type) : this(type, string.Empty) { } public TypeRegistration(Type type, string name) { Type = type; Name = name; _hashCode = string.Concat(Type.FullName, "|", Name).GetHashCode(); } public override bool Equals(object obj) { var typeRegistration = obj as TypeRegistration; if (typeRegistration == null) return false; if (Type != typeRegistration.Type) return false; if (string.Compare(Name, typeRegistration.Name, StringComparison.Ordinal) != 0) return false; return true; } public override int GetHashCode() { return _hashCode; } } private readonly SafeDictionary _RegisteredTypes; #if USE_OBJECT_CONSTRUCTOR private delegate object ObjectConstructor(params object[] parameters); private static readonly SafeDictionary _ObjectConstructorCache = new SafeDictionary(); #endif #endregion #region Constructors public TinyIoCContainer() { _RegisteredTypes = new SafeDictionary(); RegisterDefaultTypes(); } TinyIoCContainer _Parent; private TinyIoCContainer(TinyIoCContainer parent) : this() { _Parent = parent; } #endregion #region Internal Methods private readonly object _AutoRegisterLock = new object(); private void AutoRegisterInternal(IEnumerable assemblies, DuplicateImplementationActions duplicateAction, Func 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>() { 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 registrationPredicate) { // TODO - find a better way to remove "system" types from the auto registration var ignoreChecks = new List>() { 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(this); #if TINYMESSENGER // Only register the TinyMessenger singleton if we are the root container if (_Parent == null) Register(); #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 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 as second (parameters) //#if NETFX_CORE // if ((genericType == typeof(Func<,,>) && type.GetTypeInfo().GenericTypeArguments[0] == typeof(string) && type.GetTypeInfo().GenericTypeArguments[1] == typeof(IDictionary))) //#else if ((genericType == typeof(Func<,,>) && type.GetGenericArguments()[0] == typeof(string) && type.GetGenericArguments()[1] == typeof(IDictionary))) //#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 as second (parameters) //#if NETFX_CORE // if ((genericType == typeof(Func<,,>) && type.GenericTypeArguments[0] == typeof(string) && type.GenericTypeArguments[1] == typeof(IDictionary))) //#else if ((genericType == typeof(Func<,,>) && type.GetGenericArguments()[0] == typeof(string) && type.GetGenericArguments()[1] == typeof(IDictionary))) //#endif { Type returnType = genericArguments[2]; var name = Expression.Parameter(typeof(string), "name"); var parameters = Expression.Parameter(typeof(IDictionary), "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 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 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 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